What's the Fastest Way to Code a Loop in JavaScript?

I built a loop benchmarking test suite for different ways of coding loops in JavaScript. There are a few of these out there already, but I didn't find any that acknowledged the difference between native arrays and HTML collections. Since the underlying implementations are different (HTML collections for example lack the pop() and slice() methods, etc), benchmarks that don't test against both are probably missing important information.

My suspicions were confirmed. Accessing the length property is more expensive on HTML collections than on arrays, depending on the browser. In those cases, caching it made a huge difference. However, HTML collections are live, so a cached value may fail if the underlying DOM is modified during looping. On the other hand, HTML collections will never be sparse, so the best way to loop an HTML collection might just be to ignore the length property altogether and combine the test with the item lookup, since you have to do that anyway:

// looping a dom html collection
for (var i=0, node; node = hColl[i++];) {
    // do something with node
}

Another interesting result is that with HTML collections, hColl.item(i) is 2-6x slower than hColl[i], except in Safari where it's about the same. I wonder what the extra overhead is?

I've posted the results of all my benchmarks here, however my IE7 is really IE8 in IE7 emulation mode, so I mistrust these results as representing IE7's original JavaScript/DOM engine. If anybody wants to run the benchmarks in true IE7 and post the results, I'll update this post accordingly. Thanks to Kyle Simpson for the benchmarks. Also, I'm sure there are ways of looping that escaped my imagination, so if you know of any, post it in the comments and I'll add them to the test page.


[edit] To prevent overly-helpful "this script is taking too long" warnings from skewing the results, in IE you might have to edit your MaxScriptStatements registry setting. In Gecko it's dom.max_script_run_time under about:config.


Firefox 3.0.1 / OS X 10.5 / 2x3GHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 4ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {} 3ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
4ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
3ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {} 2ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
9ms
for ... in loopfor (var i in arr) {} 28ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
93ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 3ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
6ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 4ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
5ms
Array.forEach() native implementation.arr.forEach(function(x){}); 51ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
51ms
Sparse Native Array (length=12200, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 81ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {} 35ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
79ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
32ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {} 22ms
for ... in loopfor (var i in sarr) {} 30ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
96ms
Array.forEach() native implementation.sarr.forEach(function(x){}); 178ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
769ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {} 119ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {} 3ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
119ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
3ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {} 2ms
for ... in loopfor (var i in hColl) {} 97ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
163ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {} 114ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
189ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {} 95ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 235ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
98ms

Firefox 2.0 / WinXP / 1.95GHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 47ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {}16ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
31ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
16ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {}15ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
281ms
for ... in loopfor (var i in arr) {}375ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
906ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 32ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
62ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 31ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
47ms
Array.forEach() native implementation.arr.forEach(function(x){}); 391ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
422ms
Sparse Native Array (length=12634, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 453ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {}203ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
469ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
218ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {}172ms
for ... in loopfor (var i in sarr) {}328ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
875ms
Array.forEach() native implementation.sarr.forEach(function(x){}); 750ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
6000ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {} 891ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {}16ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
906ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
16ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {}15ms
for ... in loopfor (var i in hColl) {} 625ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
1188ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {} 453ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
797ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {} 437ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 1438ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
437ms

Camino 1.6.1 / OS X 10.5 / 2x3GHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 8ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {} 4ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
9ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
4ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {} 2ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
85ms
for ... in loopfor (var i in arr) {} 44ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
163ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 10ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
14ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 10ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
11ms
Array.forEach() native implementation.arr.forEach(function(x){}); 111ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
105ms
Sparse Native Array (length=11999, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 103ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {} 45ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
99ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
42ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {} 33ms
for ... in loopfor (var i in sarr) {} 52ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
151ms
Array.forEach() native implementation.sarr.forEach(function(x){}); 217ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
1338ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {} 270ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {} 4ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
270ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
4ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {} 3ms
for ... in loopfor (var i in hColl) {} 106ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
224ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {} 119ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
220ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {} 115ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 397ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
114ms

Mozilla 1.7.12 / OS X 10.5 / 2x3GHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 40ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {}14ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
22ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
13ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {} 9ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
388ms
for ... in loopfor (var i in arr) {}263ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
1126ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 27ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
48ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 26ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
32ms
Array.forEach() custom implementation.arr.forEach(function(x){}); 666ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
148ms
Sparse Native Array (length=11605, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 264ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {}157ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
255ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
180ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {}103ms
for ... in loopfor (var i in sarr) {}236ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
1027ms
Array.forEach() custom implementation.sarr.forEach(function(x){}); 1076ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
1881ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {}1888ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {}18ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
1855ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
17ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {}24ms
for ... in loopfor (var i in hColl) {} 578ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
1455ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {}1182ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
2072ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {}1102ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 2542ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
1115ms

Safari 3.1.2 / OS X 10.5 / 2x3GHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 5ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {} 3ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
6ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
4ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {} 2ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
18ms
for ... in loopfor (var i in arr) {} 42ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
80ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 5ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
8ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 5ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
7ms
Array.forEach() native implementation.arr.forEach(function(x){}); 11ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
19ms
Sparse Native Array (length=10565, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 54ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {} 31ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
71ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
45ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {} 19ms
for ... in loopfor (var i in sarr) {} 41ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
77ms
Array.forEach() native implementation.sarr.forEach(function(x){}); 285ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
482ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {} 8ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {} 3ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
8ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
4ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {} 2ms
for ... in loopfor (var i in hColl) {} 47ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
86ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {} 58ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
107ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {} 59ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 53ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
60ms

Opera 9.51 / OS X 10.5 / 2x3GHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 7ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {} 7ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
7ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
7ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {} 3ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
28ms
for ... in loopfor (var i in arr) {} 58ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
299ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 9ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
18ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 9ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
13ms
Array.forEach() native implementation.arr.forEach(function(x){}); 54ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
27ms
Sparse Native Array (length=12171, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 94ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {} 76ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
92ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
74ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {} 42ms
for ... in loopfor (var i in sarr) {} 63ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
286ms
Array.forEach() native implementation.sarr.forEach(function(x){}); 230ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
442ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {} 28ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {} 5ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
28ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
6ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {} 4ms
for ... in loopfor (var i in hColl) {} 113ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
380ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {} 36ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
60ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {} 37ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 175ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
41ms

IE 7.0.5730.11 / WinXP SP2

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 31ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {}15ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
32ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
15ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {} 0ms
do ... while loop in reverse.var i = arr.length-1; do { } while (i--);16ms
for loop in reverse.for (var i=arr.length; i--;) { }0ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
2907ms
for ... in loopfor (var i in arr) {}140ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
438ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 31ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
63ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 46ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
47ms
Array.forEach() custom implementation.arr.forEach(function(x){}); 719ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
406ms
Sparse Native Array (length=11258, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 344ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {}140ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
328ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
157ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {} 78ms
do ... while loop in reverse.var i = sarr.length-1; do { } while (i--);94ms
for loop in reverse.for (var i=sarr.length; i--;) { }93ms
for ... in loopfor (var i in sarr) {}110ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
359ms
Array.forEach() custom implementation.sarr.forEach(function(x){}); 2453ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
10922ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {}2172ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {}15ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
2125ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
16ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {}15ms
do ... while loop in reverse.var i = hColl.length-1; do { } while (i--);0ms
for loop in reverse.for (var i=hColl.length; i--;) { }16ms
for ... in loopfor (var i in hColl) {} 172ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
484ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {}1219ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
2797ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {}1406ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 3203ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
1453ms

IE 8 Beta 1 / WinXP / 1.95GHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {} 46ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {}32ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
47ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
31ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {}15ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
188ms
for ... in loopfor (var i in arr) {}203ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
734ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {} 47ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
62ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {} 47ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
47ms
Array.forEach() custom implementation.arr.forEach(function(x){}); 610ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
203ms
Sparse Native Array (length=11540, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {} 657ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {}281ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
656ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
266ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {}156ms
for ... in loopfor (var i in sarr) {}156ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
641ms
Array.forEach() custom implementation.sarr.forEach(function(x){}); 4656ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
3781ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {}3110ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {}31ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
3109ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
16ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {}31ms
for ... in loopfor (var i in hColl) {} 281ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
938ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {} 453ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
875ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {} 453ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {} 3906ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
484ms

IE 6.0 (JScript 5.6) / WinXP / 750MHZ

Native Array (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<arr.length; i++) {}121ms
For loop, but caching the length.for (var i=0, len=arr.length; i<len; i++) {}60ms
While loop that imitates a for loop.var i = 0;
while (i<arr.length) {
i++;
}
110ms
While loop that imitates a for loop, caching the length.var i=0, len=arr.length;
while (i<len) {
i++;
}
60ms
While loop in reverse, simplifying the test condition.var i = arr.length; while (i--) {}50ms
While looping by popping values (this fails on sparse arrays).var x;
while (x = arr.pop()) {}
16694ms
for ... in loopfor (var i in arr) {}781ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in arr) {
if(!isInt.test(i)){continue;}
}
2013ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; arr[i]; i++) {}141ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; arr[i]; i++) {
var x = arr[i];
}
250ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = arr[i++];) {}140ms
For reference.for (var i=0, len=arr.length; i<len; i++) {
var x = arr[i];
}
170ms
Array.forEach() custom implementation.arr.forEach(function(x){});2945ms
For reference against forEach().var f=function(x){};
for (var i=0, len=arr.length; i<len; i++) {
f(arr[i]);
}
1331ms
Sparse Native Array (length=11009, sporadically populated with 1000 items, looped 100 times)
Basic for loop.for (var i=0; i<sarr.length; i++) {}1241ms
For loop, but caching the length.for (var i=0, len=sarr.length; i<len; i++) {}671ms
While loop that imitates a for loop.var i = 0; while (i<sarr.length) {
i++;
}
1242ms
While loop that imitates a for loop, caching the length.var i = 0, len = sarr.length; while (i<len) {
i++;
}
671ms
While loop in reverse, simplifying the test condition.var i=sarr.length; while (i--) {}471ms
for ... in loopfor (var i in sarr) {}611ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in sarr) {
if(!isInt.test(i)){continue;}
}
1762ms
Array.forEach() custom implementation.sarr.forEach(function(x){});11737ms
For reference against forEach().var f=function(x){};
for (var i=0, len=sarr.length; i<len; i++) {
f(sarr[i]);
}
13359ms
HTML Collection (length=1000, looped 100 times)
Basic for loop.for (var i=0; i<hColl.length; i++) {}6349ms
For loop, but caching the length.for (var i=0, len=hColl.length; i<len; i++) {}71ms
While loop that imitates a for loop.var i = 0; while (i<hColl.length) {
i++;
}
6339ms
While loop that imitates a for loop, caching the length.var i=0, len=hColl.length; while (i<len) {
i++;
}
70ms
While loop in reverse, simplifying the test condition.var i=hColl.length; while (i--) {}50ms
for ... in loopfor (var i in hColl) {}2984ms
for ... in loop, with integer testvar isInt = /(\^[0-9]$)|(\^[1-9][0-9]+$)/;
for (var i in hColl) {
if(!isInt.test(i)){continue;}
}
5017ms
For loop, testing on existence rather than length (this fails on sparse arrays).for (var i=0; hColl[i]; i++) {}4497ms
For loop, testing on existence rather than length, plus array lookup.for (var i=0; hColl[i]; i++) {
var x = hColl[i];
}
8863ms
For loop, testing on existence rather than length, array lookup is combined with test.for (var i=0, x; x = hColl[i++];) {}4516ms
For loop, testing on existence rather than length, array lookup is combined with test, item() instead of array brackets.for (var i=0, x; x = hColl.item(i++);) {}10415ms
For reference.for (var i=0, len=hColl.length; i<len; i++) {
var x = hColl[i];
}
4587ms
Comments:

var i = somelength; do something(); while( i-- );

Posted by matt bishop on July 25, 2008 at 12:49 AM MDT #

The end result being: reverse while loops are the fastest way to iterate a basic collection, as most of us who have optimized loops have found. ;)

Thanks for the amazingly comprehensive barrage of tests confirming it though. I think this holds true for other languages, such as Actionscript.

Posted by Michael Hoskins on July 25, 2008 at 01:06 AM MDT #

> var i = somelength; do something(); while( i-- );

var i = somelength-1; do something(); while( i-- );

Posted by Greg on July 25, 2008 at 03:51 AM MDT #

> The end result being: reverse while loops are the fastest way to iterate a basic collection, as most of us who have optimized loops have found. ;)

Yes, although not necessarily the best method in all cases.

Posted by Greg on July 25, 2008 at 04:05 AM MDT #

This was a really good article. I never thought about this because the sets I loop through are pretty small.

Posted by ernest leitch on July 25, 2008 at 04:11 AM MDT #

Added do ... while to benchmark suite, just for kicks.

Posted by Greg on July 25, 2008 at 04:58 AM MDT #

@ernest - Thanks. Yeah, making all loops into reverse while loops would only serve to obfuscate your code. I'd only use the technique to cool hot spots and/or iterate large sets.

Posted by Greg on July 25, 2008 at 05:08 AM MDT #

Why is it

// looping a dom html collection
for (var i=0, node; node = hColl[i++];) {
// do something with node
}

Instead of

for(var i=0; node; node = hColl[i++]) ?

Posted by Silenius on July 25, 2008 at 03:08 PM MDT #

Node wouldn't exist for the first test so the loop would fail.

Posted by Greg on July 25, 2008 at 03:24 PM MDT #

Thanks for putting so much work into this, it was illuminating. Occasionally I don't cache my variables, I had no idea what a significant impact it made.

Posted by Jack on July 25, 2008 at 08:36 PM MDT #

I think that the reason that the while loop is faster than a for loop is because you're effectively doing comparison against zero, which is faster than other comparisons. I think you can get the same performance from a for loop by using the following:
for(var i = arr.length - 1; i>=0; i--){}

Posted by Simon Hartley on July 27, 2008 at 08:03 PM MDT #

> sarr.forEach(function(x){});

Your test shows that this is definitly not a good solution.

While everyone wants to add closures everywhere, this shows that we have to be carreful and not use them on large collection...

Posted by Fluminis on July 27, 2008 at 11:54 PM MDT #

What about:

for(var i=arr.length; --i >= 0;){}

It does array length caching and comparison with zero...

Posted by Michael Lee on July 28, 2008 at 04:46 AM MDT #

> sarr.forEach(function(x){});

I think the performance hit probably comes from building a new scope object for the anonymous function for each item. Not sure if this is a true closure. There's also a lookup for each array item (x) that should be factored out, since most loops have to do it anyway.

Posted by Greg on July 28, 2008 at 04:47 AM MDT #

@Simon Hartley, @Michael Lee

Thanks. I added a reverse for loop to the benchmark. Except I left out the zero comparison since it's not strictly needed:

for (var i=arr.length; i--;) { }

Posted by Greg on July 28, 2008 at 05:04 AM MDT #

Here's the true IE7 (7.0.5730.11) WinXP SP2 benchmark results:

http://www.flensed.com/IE7-looping.html

\*\*note: In IE7, it prompted me about 5 or 6 times if I wanted to stop a long running script. I clicked "no" as soon as I could for each alert (almost immediately each time), but I'm not really sure if that would sway results or not.

Posted by Kyle Simpson on July 28, 2008 at 05:04 AM MDT #

What about this for a HTML collection. I use it sometimes, but I never speed tested it.
var e, i = 0;
while (e = hColl[i++]) {

}
You have the for loop equivalent, but not the while.

Posted by Declan on July 28, 2008 at 06:19 AM MDT #

Sorry, I should have made a note of this. I had to edit a registry setting to prevent this from happening on IE. Those delays almost certainly blew out a few of the results. Google MaxScriptStatements for instructions.

Posted by Greg on July 28, 2008 at 06:19 AM MDT #

I don't think it's worth adding a while equivalent to every for loop in the benchmark. The existing ones already show the difference (which is negligible IMO).

Posted by Greg on July 28, 2008 at 06:37 AM MDT #

@Greg: Right you are. The zero comparison isn't necessary when working with array lengths, unless of course it's possible that the array's length was intentionally altered...

Looks like the reverse for loop with caching is about as fast as the reverse while loop and sometimes faster. Can you update the blog post to show this?

Posted by Michael Lee on July 28, 2008 at 06:39 AM MDT #

@Michael - I'm (apparently) approaching Roller's internal size limit for blog posts. I might do a summary post after comments trail off.

Posted by Greg on July 28, 2008 at 06:56 AM MDT #

@Greg... ok, I will re-run with that registry tweak in place and let you know when I update the link.

Posted by Kyle Simpson on July 28, 2008 at 07:59 AM MDT #

Were you using Firefox 3.0.1? (Firefox 3.1 is not released yet).

What version of JScript were you using with IE6 (it makes a huge difference)?

Posted by anon on July 28, 2008 at 08:06 AM MDT #

Whoops. Corrected. Firefox 3.0.1.

Posted by Greg on July 28, 2008 at 08:33 AM MDT #

The IE6 was JScript 5.6

Posted by Greg on July 28, 2008 at 08:52 AM MDT #

[Trackback] WebIntroductiontoJavascriptAnimationWhat'stheFastestWaytoCodeaLoopinJavaScript?.NET...

Posted by gOODiDEA on July 28, 2008 at 11:15 AM MDT #

[Trackback] Web Introduction to Javascript Animation What's the Fastest Way to Code a Loop in JavaScript? .NET Some

Posted by gOODiDEA.NET on July 28, 2008 at 11:16 AM MDT #

@Greg:
Ok, the link has been updated with a pure run of the benchmark tests on IE7 (7.0.5730.11) on WinXP SP2.

http://www.flensed.com/IE7-looping.html

Posted by Kyle Simpson on July 28, 2008 at 12:16 PM MDT #

Hi, interesting post.
I made a benchmarker some time ago, I made a loop comparison (generic loops).

If you're interested, here's the link: http://benchmarker.flesler.com/
Choose the test called 'loops'.

Cheers

Posted by Ariel Flesler on July 28, 2008 at 01:41 PM MDT #

@Kyle - Thanks. Updated the tables.

Posted by Greg on July 28, 2008 at 02:25 PM MDT #

@Ariel - Interesting. I see you did some loop unrolling. Funny, they all performed virtually the same on FF3.

Posted by Greg on July 28, 2008 at 02:41 PM MDT #

For me too, but not in other browsers.
I also noticed that Firefox seems unreliable for benchmarks, even after turning firebug off (very important!).
The results always seemed to vary more than one would accept.
On the other hand IE, Opera and Safari seemed to be more or less stable.

Posted by Ariel Flesler on July 29, 2008 at 07:52 AM MDT #

[Trackback] 1.微软公司宣布发布VirtualEarth

Posted by 真见 on July 29, 2008 at 01:58 PM MDT #

[Trackback]

Posted by 真见 on July 29, 2008 at 02:07 PM MDT #

In reference to the various comments about reverse counting, the reason checking against 0 is faster then <length, etc is that the ordinal operators <,<=,>, and >= are polymorphic (in the general case -- a sufficiently advanced interpreter may be able to infer types perhaps?) so these operators require type checks on both left and right sides of the operator to determine what comparison behaviour should be used.

In general you should also use the strict === rather than ==, as == will eventually fall back on toString conversion and string comparison.

Posted by Oliver on July 29, 2008 at 03:40 PM MDT #

Post a Comment:
Comments are closed for this entry.
About

My name is Greg Reimer and I'm a web technologist for the Sun.COM web design team.

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today