Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Here's some code that I ran through jsperf to assess its performance. The first test (named EvalLengthBefore++ in the images below) is the way I would consider normally looping through the elements of an array:

var arr = [];
for (var x = 0; x < 1000; x++) {
  arr.push(Math.random());
}

var len = arr.length;
for (var y = 0; y < len; y++) {
  //do some maths
  var el = arr[y];
  el++; //meaningless operation
}

The second test (named InfiniteLoopWithBreak in the images below) is the method I found in some code that is supposed to to be run in IE7 (it's part of a CSS fallback):

var arr = [];
for (var x = 0; x < 1000; x++) {
  arr.push(Math.random());
}

for (var y = 0;; y += 1) {
  //do some maths
  var el = arr[y];
  if (!el) {
    break;
  }
  el++;
}

In modern browsers, the second method is much slower, which is kind of what I expected. However in IE7 it is just as fast, occasionally faster, in the jsperf tests:

Test results in Chrome: Test in Chrome

Test results in IE7 enter image description here

Here are the jsperf tests if you want to run them yourselves.

Why is the second code snippet faster than the rest in IE7?

share|improve this question
8  
Not sure if this belongs to codereview.SE but it does look like a pretty interesting question. –  Josay Oct 3 '13 at 15:20
    
@Josay, I debated for a while whether it was more suited to here or Stack Overflow, but settled for here in the end. Happy to have the question migrated if the mods feel it would be more suitable over at SE. –  Andy F Oct 3 '13 at 15:22
    
Yeah, I'd wait for the mods to decide. However, this doesn't quite fit "understanding code snippets" because because you already know what's happening. You just want to know why. –  Jamal Oct 3 '13 at 17:14
    
would be interesting to test also for (var el, y = 0; el = arr[y]; y++) { el++; } –  Stuart Oct 3 '13 at 19:29
1  
@AndyF: A very interesting question, I must say. Sadly, I think programmers.stackexchange or (though borderline) even computerscience.stackexchange. Anyway, I've posted a (rather verbose) answer here anyway... ;P –  Elias Van Ootegem Oct 4 '13 at 10:09
add comment

4 Answers 4

up vote 11 down vote accepted

The short answer:
In your code the arr.length is the major bottleneck. Simly because of the differences between the various implementations of JavaScript. Not only the implementations differ, but also what the engines actually do prior to executing your code.
Why do I think this: simple:

for([[expr evaluated at start of loop]];
    [[expr re-evaluated on each iteration + 1(end of loop)]];
    [[expr evaluated for each iteration +1(end of loop)]]
)

The cases that are fastest on IE7 are those where the conditional expression in the for-loop is either missing or is simply comparing the values of 2 variables.

The long answer, without focussing on arr.lenght, but keep in mind that here, you're getting a property of an object, that is, sort-of, inherited from the prototype.

The reason why is simply because of how Chrome's V8 compiles the code, and how the Object[[GetPropery]] is implemented. Since JS arrays are just augmented objects (Array instanceof Object is true), getting a value from an array is, essentially the same as someObj.someProp.
Most JS implementations use either a HashMap or HashTable for the objects. Chrome's V8 engine, is a bit of an odd one out, in a couple of crucial ways.

FF's SpiderMonkey/*Monkey engines compile JS code to intermediate byte-code, that runs on a virtual machine.
Their Rhino engine compiles JS to Java, which is also a VM environment. Cf the hybrid model in the img below
JS "engines" of old didn't even go that far, they were just parse-and-execute things. They did no or very little optimization or reflection on the code they were asked to parse.
V8 does things a bit different: it parses, optimizes and compiles the resulting AST (Abstract Syntax Tree) straight into machine-executable code. No byte-code virtual-machine stuff to hold you back:

JS engines compilation models

So, Chrome's V8 compiles to machine code, which cuts down overall execution time (in most cases). In addition to that, the V8 engine does not use a HashTable for object properties. It creates classes:

To reduce the time required to access JavaScript properties, V8 does not use dynamic lookup to access properties. Instead, V8 dynamically creates hidden classes behind the scenes.

What does this mean for arr.length:

//V8:
arr = [];//creates class, that has lenght property, value 0
arr.push(123);//arr points to class with property 0 = 123, length = 1

That means that, arr.lenght or arr[0] both are simple, atomic operations. Interms of time-complexity, they are as close as makes no difference both: O(1). Now, I'm not familiar with the internals of IE's JScript engine, but I'm prepared to take a punt on how arr.length works:

arr.length;//->arr @instancelevel->search(length)
             //
             ==>arr.prototype->search(length)
                 //
                 ==> magic property, probably does something like:
                     return max(@instance.keys) +1

Now, this may range anywhere from pretty accurate to down-right absurd, but the principle stands: getting the length property from an array on engines that don't create classes for instances, is not atomic, and therefore slower.
Sadly, because of MS's software being closed source, I can't tell you what kind of AST the parser churns out, nor what the engine then does with that AST. You'll have to get friendly with someone working in Redmond, or send a very polite email, requesting more info (don't expect an answer, though :-P).

So, V8 compiles the AST directly to machine-executable code, and creates classes to speedup property. In theory, accessing a property in JS, running on V8 should be almost as fast as C++ code. In theory, that is :P.
Internet Explorer's JScript engine, especially IE7, is quite dated. It doesn't do optimization very well. It doesn't compile JS as well as modern day engines do.

I can't finde the resource ATM, but I also seem to remember that IE's JScript implementation of objects was, in fact, rather lacking, too. I seem to recall it didn't even use a full-blown HashTable for its objects, which would explain why someArray.length takes ages (since it requires a prototype lookup).

Read more here.

share|improve this answer
add comment

Since you asked this question here rather than on Stack Overflow, I'm going to propose this countdown iteration:

for (var y = arr.length - 1; y >= 0; --y) {
    //do some maths
    var el = arr[y];
    el++;
}

The advantages are:

  • You only calculate arr.length once, and do so without introducing a temporary variable
  • Each iteration, you compare y with zero. To compare with any other number, the CPU would first have to load both values into registers before executing the conditional branch instruction. To compare against zero, only the value of y needs to be loaded in a register; there is a special instruction for comparing against zero and conditionally branching.

That said, the performance gain by iterating backward instead of forward is negligible, and you should avoid the countdown technique if

  • The processing of an element depends on the value of another element
  • The processing of an element could fail — premature termination of the loop would be weird if the partial results are at the end of the array
share|improve this answer
add comment

To start with, it might be that IE7 is so slow, you can't really tell the differences with such small numbers. Another factor might be that "length" calculation is really slow on an array this size (well, back then ...) and that array access is "optimized" (at least better, and doesn't hurt much more than static property access). But I think that IE7's just too slow for us to notice.

share|improve this answer
add comment

First of all, microbenchmarks like these don't really tell the whole story. It may only be "fast" or "slow" in this case. In real-world scenarios, it may tell another story (like when you have to deal with stuff other than just arrays).

Another thing is, with such small numbers in the IE tests... you can't really say it's fast :D

Another thing is (and most likely this would be the cause of the great divide in Chrome) is that modern JS compilers tend to optimize "hot code". Other forms of code are internally faster as well due to the browser's implementation of operations.

So in this case, case 2 and case 4 in Chrome might have been optimized internally, whereas case 3 might have been faster for IE7.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.