It's 20:30 and I'm after a 6 hour bug hunt of an irritating bug caused by an uninitialized member variable.
In the our previous version we had the next few lines of code:
var aList = new Array;
for (var iDx=0; iDx < nNumOfElements; iDx++)
{
// Some code
aList.nCount = someValue; //This line
}
aList.sort(function(a, b) { return b.nCount - a.nCount ; });
In the last release someone accidentally removed the line with comment.
and there was no other initialization of the member variable nCount.
Some of our clients got a "Number expected" exception which is pretty obvious (in retrospect), strangely the error doesn't reproduce with our Q.A. nor 80% of our clients!
How can it be? is there any strict mode that we can run with that will find such pesky bugs? what is the difference between the clients that got the exception and ones that didn't (it's not browser version nor windows version)
(our system runs only on IE6+ in a special container which makes it hard for us to write the code in normal I.D.E.'s we pretty much write it all in notepad ++)
You wrote int instead of var. I do that all the time...
int iDx=0 should be var iDx=0.
By the way, what editor are you using? int is a "future reserved word" in ES, so a good editor may highlight it in an ugly way (gedit makes it red with a red underline by default) to bring your attention to it.
Looks like it's a bug with IE6 related to array sorting.
Try some of the workarounds suggested here...
Related
I have been unable to find any reference to this statement in any book, manual, or site. As far as I can tell, it functions exactly as a // comment. For example:
console.log("1");
--> console.log("2");
console.log("3");
will print
1
3
What I'm curious about is exactly what the difference between --> and // is, if any exists, and also why --> seems to completely absent from all the JavaScript references I've seen - the only reason I found out about it at all was because I accidentally typed it into Adobe Dreamweaver, and it was highlighted as a comment. Thanks!
Edit: Here is a functional jsFiddle demonstrating the behavior.
Edit 2: I've tested further, and I've discovered a few things.
This only works if there are exactly two dashes. -> and ---> will throw errors.
This only works with a "greater than" symbol. --< will throw an error.
This will not work in the middle of or at the end of a line. console.log("1"); --> console.log("2"); will throw an error.
My guess is that the JavaScript engine, forgiving as always, is silently ignoring the line because it looks like the end of an HTML comment (<!-- -->). JavaScript inlined in HTML has historically been wrapped in an HTML comment so that browsers that don't support JavaScript would not try to parse it.
Edit:
I've done some research, and this is indeed the case.
From V8's scanner.cc:
If there is an HTML comment end '-->' at the beginning of a
line (with only whitespace in front of it), we treat the rest
of the line as a comment. This is in line with the way
SpiderMonkey handles it.
From Rhino's Comment.java:
JavaScript effectively has five comment types:
// line comments
/* block comments */
/** jsdoc comments */
<!-- html-open line comments
^\s*--> html-close line comments
The first three should be familiar to Java programmers. JsDoc comments
are really just block comments with some conventions about the formatting
within the comment delimiters. Line and block comments are described in the
Ecma-262 specification.
Note that the --> comment is not part of the Ecma-262 specification.
This is not a comment. If you see it as a comment inside of code, then its probably showing as some kind of hanging chad HTML comment instead of the normal "//".
What's happening in this case is you are comparing using the greater than and then subtracting 1. Here are some examples...
var x = 3; var y = 3; console.log(x --> y);
false and x is now 2
If you place the normal comment characters "//", you'll get a syntax error (which you should)
The reason this is working as a comment is because it is returning as undefined. This is not safe to use as a comment. Oddly enough, it works fine in Chrome and you can throw all kinds of characters at it if you start the line with "-->".
--> something for nothing ~!####%$#%^$&%^&*()_+_=-=[]\];'\||?>;';;; alert('test'),,143187132458
However, within IE 11, it is always a syntax error. Very cool find
I'm making a library, and I often inspect the result of Closure Compiler's output to see how it's doing things (I do have unit tests, but I still like to see the compiled code for hints of how it could compress better).
So, I found this very weird piece of code, which I never seen before.
variable : {
some();
code()
}
Note: this is not an object literal! Also, there is no ? anywhere that would make it a ?: conditional.
That code is in a regular function block (an IIFE).
variable, in this case, is an undefined variable. There's no code making it true, false, or whatever, and just to make sure, I put a console.log in there and indeed, I get a ReferenceError.
Please do note that I test my code in IE8 too, so this isn't just in modern browsers. It seems to be standard, plain old javascript.
So let's experiment with it. Firing up Chrome's console, I get this:
undeclaredVariable:{console.log('does this get logged?')} // yes it does.
trueValue:{console.log('what about this?')} // same thing.
falseValue:{console.log('and this?')} // same thing.
but then...
(true):{console.log('does this work too?')} // SyntaxError: Unexpected token :
...and...
so?{console.log('is this a conditional?')}:{alert(123)} // Unexpected token .
So what does it do?
thisThing:{console.log('is used to declare a variable?')}
thisThing // ReferenceError: thisThing is not defined
Please, I'd love it if someone could explain to me what this code is meant to do, or at least what it does.
It is a label
Provides a statement with an identifier that you can refer to using a
break or continue statement.
For example, you can use a label to identify a loop, and then use the
break or continue statements to indicate whether a program should
interrupt the loop or continue its execution.
Another common place you see it is when people stick the wonderful and useless javascript: on event handlers.
This is a label (the bit ending with a colon) followed by a block (the code surrounded by the curly brackets).
Blocks usually follow control statements, like if(...) { /*block*/ }, but they can also simply stand on their own, as in your example.
Labels allow jumping up several loops at a time with a continue or break; see the linked MDN page for several examples, such as:
var itemsPassed = 0;
var i, j;
top:
for (i = 0; i < items.length; i++){
for (j = 0; j < tests.length; j++)
if (!tests[j].pass(items[i]))
continue top;
itemsPassed++;
}
Here, top: is a label that code inside the inner loop can jump to, in order to escape to the outer loop.
For the sake of anyone who doesn't know what JSON is, and sees a colon in what might actually be an object, and is trying to figure out what it is, and finds this discussion, a colon is also used in JSON. There is a practice of embedding functions in a JSON object. Which might be confusing (As it was to me) for anyone who happens to see this for the first time. (Everyone isn't born with the knowledge of JSON and JavaScript programmed into their brains.) So if you find yourself at this discussion, and you think that every time you see a colon in JavaScript, that it's a label, it might not be. It might be that it's a colon after a label, OR it might be part of JSON. In fact, a colon in JSON being shown as a string, is a lot more common than a label. JSON in the form of an object, will be displayed as [object Object], with all the content hidden. So, unless the JSON is in the form of a string, and you display an object to the console (console.log(object)) all you will see is [object Object]. It is common practice to write JavaScript code, wrapped in an object. In that case you will see the JSON in the form of code. That's when you'll ask yourself, "What is this? and what is that colon for?" Then you'll find yourself at this discussion, and be told that it's a label, when it's really part of JSON. The topic of this discussion is worded: "Please explain this usage of a colon in javascript", and then the "correct answer" is marked as having to do with a label. The correct answer is that a colon can be used in more than one way. So, if you don't know what JSON is, or think you know (like I did, but didn't really understand) read about it here:
JSON.org
That is just a label.
you can use continue [label name] (or break) in a loop to go to a label.
More explanations of what they are can be seen throughout the interwebs.
it is used for labeling an statement in jsvascript.check more detail here.
the labeled statement can be used with break and continue later.
We found a severe problem with the interpretation of our Javascript code that only occurs on iOS 5/Safari 6 (then current iPad release) that we think is due to critical bug in the Just in Time JS compiler in Safari. (See updates below for more affected versions and versions that seem to now contain a fix).
We originally found the issue in our online demos of our library: the demos crash more or less randomly but this happens only the second time (or even later) that the same code is executed. I.e. if you run the part of the code once, everything works OK, however subsequent runs crash the application.
Interestingly executing the same code in Chrome for iOS the problem does not show, which we believe is due to the missing JIT capabilities of the Webview that is used in Chrome for iOS.
After a lot of fiddling we finally think we found at least one problematic piece of code:
var a = 0; // counter for index
for (var b = this.getStart(); b !== null; b = b.getNext()) // iterate over all cells
b.$f = a++; // assign index to cell and then increment
In essence this is a simple for loop that assigns each cell in a linked list data structure its index. The problem here is the post-increment operation in the loop body. The current count is assigned to the field and updated after the expression is evaluated, basically the same as first assigning a and then incrementing it by one.
This works OK in all browsers we tested and in Safari for the first couple of times, and then suddenly it seems as if the counter variable a is incremented first and then the result is assigned, like a pre-increment operation.
I have created a fiddle that shows the problem here: http://jsfiddle.net/yGuy/L6t5G/
Running the example on an iPad 2 with iOS 6 and all updates the result is OK for the first 2 runs in my case and in the third identic run suddenly the last element in the list has a value assigned that is off by one (the output when you click the "click me" button changes from "from 0 to 500" to "from 0 to 501")
Interestingly if you switch tabs, or wait a little it can happen that suddenly the results are correct for two or so more runs! It seems as if Safari sometimes resets is JIT caches.
So since I think it may take a very long for the Safari team to fix this bug (which I have not yet reported) and there may be other similar bugs like this lurking in the JIT that are equally hard to find, I would like to know whether there is a way to disable the JIT functionality in Safari. Of course this would slow down our code (which is very CPU intensive already), but better slow than crashing.
Update:
Unsurprisingly it's not just the post increment operator that is affected, but also the post decrement operator. Less surprisingly and more worryingly is that it makes no difference if the value is assigned, so looking for an assignment in existing code is not enough. E.g. the following the code b.$f = (a++ % 2 == 0) ? 1 : 2; where the variables value is not assigned but just used for the ternary operator condition also "fails" in the sense that sometimes the wrong branch is chosen. Currently it looks as if the problem can only be avoided if the post operators are not used at all.
Update:
The same issue does not only exist in iOS devices, but also on Mac OSX in Safari 6 and the latest Safari 5:
These have been tested and found to be affected by the bug:
Mac OS 10.7.4, Safari 5.1.7
Mac OS X 10.8.2, WebKit Nightly r132968: Safari 6.0.1 (8536.26.14, 537+). Interestingly these do not seem to be affected: iPad 2 (Mobile) Safari 5.1.7, and iPad 1 Mobile Safari 5.1. I have reported these problems to Apple but have not received any response, yet.
Update:
The bug has been reported as Webkit bug 109036. Apple still has not responded to my bug report, all current (February 2013) Safari versions on iOS and MacOS are still affected by the problem.
Update 27th of February 2013:
It seems the bug has been fixed by the Webkit team here! It was indeed a problem with the JIT and the post-operators! The comments indicate that more code might have been affected by the bug, so it could be that more mysterious Heisenbugs have been fixed, now!
Update October 2013:
The fix finally made it into production code: iOS 7.0.2 at least on iPad2 does not seem to suffer from this bug anymore. I did not check all of the intermediate versions, though, since we worked around the problem a long time ago.
Try-catch blocks seem to disable the JIT compiler on Safari 6 on Lion for the part directly inside the try block (this code worked for me on Safari 6.0.1 7536.26.14 and OS X Lion).
// test function
utility.test = function(){
try {
var a = 0; // counter for index
for (var b = this.getStart(); b !== null; b = b.getNext()) // iterate over all cells
b.$f = a++; // assign index to cell and then increment
}
catch (e) { throw e }
this.$f5 = !1; // random code
};
This is at least a documented behavior of the current version of Google's V8 (see the Google I/O presentation on V8), but I don't know for Safari.
If you want to disable it for the whole script, one solution would be to compile your JS to wrap every function's content inside a try-catch with a tool such as burrito.
Good job on making this reproducible!
IMO, the correct solution is to report the bug to Apple, then workaround it in your code (surely using a separate a = a + 1; statement will work, unless the JIT is even worse than you thought!). It does indeed suck, though. Here's a list of common things you can also try throwing in to the function to make it de-optimise and not use JIT:
Exceptions
'with' statement
using arguments object, e.g. arguments.callee
eval()
The problem with those is if the Javascript engine is optimised to JIT them before they fix that bug, in which case you're back to crashing. So, report and workaround!
Actually, the FOR loop bug is still present in Safari on iOS 7.0.4 in iPhone 4 and iPad 2. The loop failing can be significantly simpler than the illustration above, and it rakes several passes through the code to hit. Changing to a WHILE loop allows proper execution.
Failing code:
function zf(num,digs)
{
var out = "";
var n = Math.abs(num);
for (digs; digs>0||n>0; digs--)
{
out = n%10 + out;
n = Math.floor(n/10);
}
return num<0?"-"+out:out;
}
Successful code:
function zf(num,digs)
{
var out = "";
var n = Math.abs(num);
do
{
out = n%10 + out;
n = Math.floor(n/10);
}
while (--digs>0||n>0)
return num<0?"-"+out:out;
}
I've got a c# foreach loop that Is outputting some javascript to initialize some progress bars on my razor view.
#foreach (var item3 in Model)
{
#:$("#campaignMeter-#item3.ID").wijprogressbar({ value: #((item3.TotalRedeemed / item3.TotalSold) * 100), fillDirection: "east" });
}
The problem I'm having is visual studio is reporting "Conditional Compilation is Turned Off" on the foreach loop, and the small calculation for value is always coming out as 0, despite TotalRedeemed and TotalSold having values. Am I using the #: operator properly? Thanks for your help.
I've tried both suggestions so far and this is what I currently have:
#foreach (var item3 in Model)
{
var percentage = (item3.TotalRedeemed / item3.TotalSold) * 100;
<text>$("#campaignMeter-#item3.ID").wijprogressbar({ value: #percentage, fillDirection: "east" });</text>
}
percentage is coming out as 0, but TotalRedeemed and TotalSold have values, as they are printed on the view before this is called. Is there a way to set a break point on my view to see what percentage is before its printed?
Timmi4sa - I agree, there isn't much of an answer as to why we are getting this error. I finally got a step closer to understanding it all so I thought i would share.
Conditional Compilation is defined my MS as this:
Conditional compilation enables JScript to use new language features
without sacrificing compatibility with older versions that do not
support the features. Some typical uses for conditional compilation
include using new features in JScript, embedding debugging support
into a script, and tracing code execution.
From what I can tell, we are really talking about a feature of VS. My current guess is this: VS lets you debug JS, but it has to know what the JS is in order to debug it. By default Conditional Compilation is off - I am guessing that there is some additional overhead involved. What we are doing when we are using #Model... in JS is doing exactly what the warning states (more or less) - creating conditional JS. The JS ends up being different things depending on the value of our C#/VB variables.
According to MS the solution is to turn Conditional Compilation on as mentioned above via the statement:
/*#cc_on #*/
While I tend to be a bit anal and prefer to avoid warnings, this may be one I just simply ignore (unless someone can educate me further as to why this is a bad idea).
If you really want the error to go away and do not like the Conditional Compilation flag, you can wrap the C#/VB code call in double quotes like below. But this feels dirty and only works because JS is loosely typed... (well with numeric types anyway, strings shouldn't have a problem... regardless, this feels hacky)
"#Model.Items.Count()"
Edit: I went and did a little more research... I like the idea of CC even less after skimming this article: http://www.javascriptkit.com/javatutors/conditionalcompile.shtml. I think I will just be ignoring this warning.
I hope that helps explain away some of the mystery.
EDIT :
Another option is to throw a HiddenFor down on the form, give it an Id and then populate a JS variable from that field (jQuery makes this pretty easy). This is what I ended up doing for the time being. It eliminates warnings and I often want to compare the JS variable back to the original VMC field anyway. For those of you who need it:
#* Somewhere in your form - assuming a strongly typed view *#
#Html.HiddenFor(x => x.YourField, new { id = "SomethingMeaningful" })
// and then in your JS
$(document).ready(function(){
...
var jsYourField = $("#SomethingMeaningful").val();
...
});
Please note that JS variable and MVC variables do not always 'line up' exactly right so you may need to do some casting or additional work when you copy the variable value into your JS.
Add /*#cc_on #*/ in your code.
Update: Found out why they could be 0:
item3.TotalRedeemed and item3.TotalSold need to be float or double. If they are int, it comes out to 0.
Try this:
#foreach (var item3 in Model)
{
<text>$("#campaignMeter-#item3.ID").wijprogressbar({
value: #((item2.TotalRedeemed / item2.TotalSold) * 100),
fillDirection: "east"
});</text>
}
But a better approach would be to perform this calculation on a view model property, so that your view looks like this:
#foreach (var item in Model)
{
<text>$('#campaignMeter-#(item.ID)').wijprogressbar({
value: #item.SoldPercentage,
fillDirection: "east"
});</text>
}
I thought I would share what worked for me,
I had this same issue : System.Web.HttpCompileException (0x80004005)
below the exception I get: The name 'Url' does not exist
When I looked at the View I noticed the only place that was using Url was the razor code #Url.
This post talked about the references to razor and MVC.
When i looked in the Views folder in the solution there was a web.config file that contained all the references however it was renamed web.src.config. As soon as I changed it to web.config I was up and running again.
This is probably the beginning of many questions to come.
I have finished building my site and I was using Firefox to view and test the site. I am now IE fixing and am stuck at the first JavaScript error which only IE seems to be throwing a hissy about.
I run the IE 8 JavaScript debugger and get this:
Object doesn't support this property or method app.js, line 1 character 1
Source of app.js (first 5 lines):
var menu = {};
menu.current = "";
menu.first = true;
menu.titleBase = "";
menu.init = function(){...
I have tested the site in a Webkit browser and it works fine in that.
What can I do to fix this? The site is pretty jQuery intensive so i have given up any hope for getting it to work in IE6 but I would appreciate it working in all the others.
UPDATE: I have upload the latest version of my site to http://www.frankychanyau.com
In IE8, your code is causing jQuery to fail on this line
$("title").text(title);
in the menu.updateTitle() function. Doing a bit of research (i.e. searching with Google), it seems that you might have to use document.title with IE.
Your issue is (probably) here:
menu.updateTitle = function(hash){
var title = menu.titleBase + ": " + $(hash).data("title");
$("title").text(title); // IE fails on setting title property
};
I can't be bothered to track down why jQuery's text() method fails here, but it does. In any case, it's much simpler to not use it. There is a title property of the document object that is the content of the document's title element. It isn't marked readonly, so to set its value you can simply assign a new one:
document.title = title;
and IE is happy with that.
It is a good idea to directly access DOM properties wherever possible and not use jQuery's equivalent methods. Property access is less troublesome and (very much) faster, usually with less code.
Well, your line 1 certainly looks straight forward enough. Assuming the error line and number is not erroneous, it makes me think there is a hidden character in the first spot of your js file that is throwing IE for a fit. Try opening the file in another text editor that may support display of normally hidden characters. Sometimes copying/pasting the source into a super-basic text-editor, like Notepad, can sometimes strip out non-displayable characters and then save it back into place directly from Notepad.