views:

1542

answers:

11

In the past and with most my current projects I tend to use a for loop like this:

var elements = document.getElementsByTagName('div');
for (var i=0; i<elements.length; i++) {
    doSomething(elements[i]);
}

I've heard that using a "reverse while" loop is quicker but I have no real way to confirm this:

var elements = document.getElementsByTagName('div'), 
    length = elements.length;

while(length--) {
    doSomething(elements[length]);
}

What is considered as best practice when it comes to looping though elements in JavaScript, or any array for that matter?

+7  A: 

At the risk of getting yelled at, i would get a javascript helper library like jquery or prototype they encapsulate the logic in nice methods - both have an .each method/iterator to do it - and they both strive to make it cross-browser compatible

Per Hornshøj-Schierbeck
@Hojou - Obviously I use the respective javaScript libraries for many projects - they are time-savers and don't cause me as many headaches but with some smaller projects I find it's better to write my own methods. jQuery is definitely my favourite though due its fantastic simplicity!
J-P
Why employ a library to perform a simple task ?-)
roenving
I know, i know. I just like including jquery to minimize the risk of introducing a cross-browser imcompatibility issue. You don't need a lot of code in your 'doSomething' to posibly introduce one of those errors.
Per Hornshøj-Schierbeck
Honestly, jQuery just to deal with loops? Insanity.
Tim Down
@Tim: In reality I think there are very few sites i would create using javascript, where adding jquery would be insanity? What are the complications of using jquery compared not to?
Per Hornshøj-Schierbeck
Sorry, I was perhaps a little harsh. In brief, using jQuery means the user's browser has to download 50K of JavaScript, which may bring a significant performance hit (on a mobile device, for example). For that price, jQuery (or any library) should be delivering significant benefit to the user. I don't think providing an iterator function qualifies, particularly when there's no browser incompatibilities with loops to be worked round.
Tim Down
You are right about the performance hit - especially regarding such devices as mobile :) I guess it depends a lot on the target audience and size of the website generally. I totally agree that adding jquery would be crazy if you're creating a 'simple' website. I'm just colored from my world (classifieds/newspaper/administration websites). Depends on the context, ofcourse...
Per Hornshøj-Schierbeck
+5  A: 

I think using the first form is probably the way to go, since it's probably by far the most common loop structure in the known universe, and since I don't believe the reverse loop saves you any time in reality (still doing an increment/decrement and a comparison on each iteration).

Code that is recognizable and readable to others is definitely a good thing.

Adam Bellaire
A: 

I know that you don't want to hear that, but: I consider the best practice is the most readable in this case. As long as the loop is not counting from here to the moon, the performance-gain will not be uhge enough.

Georgi
Agreed. If you're counting backwards, write a comment that says "its merely a speed issue", then anyone who wants to edit your code won't be confused by it.
Ali
+3  A: 

I too advise to use the simple way (KISS !-)

-- but some optimization could be found, namely not to test the length of an array more than once:

var elements = document.getElementsByTagName('div');
for (var i=0, im=elements.length; im>i; i++) {
    doSomething(elements[i]);
}
roenving
A nice improvement actually... Definitely going to use this on all my "for" loops from now on! thank you!
J-P
Unless what happens within doSomething() could change the total number of elements in the array.
Ken Ray
@Ken Ray: Then it's not a for-loop you should use ...
roenving
A: 

I prefer the for loop as it's more readable. Looping from length to 0 would be more efficient than looping from 0 to length. And using a reversed while loop is more efficient than a foor loop as you said. I don't have the link to the page with comparison results anymore but I remember that the difference varied on different browsers. For some browser the reversed while loop was twice as fast. However it makes no difference if you're looping "small" arrays. In your example case the length of elements will be "small"

Gene
+5  A: 

Note that in some cases, you need to loop in reverse order (but then you can use i-- too).

For example somebody wanted to use the new getElementsByClassName function to loop on elements of a given class and change this class. He found that only one out of two elements was changed (in FF3).
That's because the function returns a live NodeList, which thus reflects the changes in the Dom tree. Walking the list in reverse order avoided this issue.

var menus = document.getElementsByClassName("style2");
for (var i = menus.length - 1; i >= 0; i--)
{
  menus[i].className = "style1";
}

In increasing index progression, when we ask the index 1, FF inspects the Dom and skips the first item with style2, which is the 2nd of the original Dom, thus it returns the 3rd initial item!

PhiLho
A good point, though I wouldn't advise to change the className on the fly, as it forces the browser to recalculate the rendering of the entire document ...
roenving
+2  A: 

I like doing:

 
var menu = document.getElementsByTagName('div');
for (var i = 0; menu[i]; i++) {
     ...
}

There is no call to the length of the array on every iteration.

A very quick test (directly in my editors browser) shows that a thousand iterations isn't possible to tell time for, with your scheme it says 15 ms, with the original testing the length for each iteration it's 31 ms ...
roenving
Hrm, a little to fast: Using one test on the array-length it says 0 ms ...
roenving
Just make sure you don't start using this on arrays where null,undefined,false,0,"" are valid elements!
Ali
+6  A: 

LOOP benchmarks galore!

roosteronacid
awesome! I know I will be referencing this page a lot
Causas
+1  A: 

You might also check out this page on my site where I compare the speed of an incrementing for loop, a reverse do/while loop and Duff's Device.

Andrew Hedges
But this isn't a real-world scenario for fetching elements ... I just tried to run a test on an array, where you in every loop had to get hold of the element in the array, fastest was optimized simple iteration, reverse do/while last !-) See new answer with testresults ...
roenving
+2  A: 

Also see my comment on Andrew Hedges' test ...

I just tried to run a test to compare a simple iteration, the optimization I introduced and the reverse do/while, where the elements in an array was tested in every loop.

And alas, no surprise, the three browsers I tested had very different results, though the optimized simple iteration was fastest in all !-)

Test:

An array with 500,000 elements build outside the real test, for every iteration the value of the specific array-element is revealed.

Test run 10 times.

IE6:

Results:

Simple: 984,922,937,984,891,907,906,891,906,906

Average: 923.40 ms.

Optimized: 766,766,844,797,750,750,765,765,766,766

Average: 773.50 ms.

Reverse do/while: 3375,1328,1516,1344,1375,1406,1688,1344,1297,1265

Average: 1593.80 ms. (Note one especially awkward result)

Opera 9.52:

Results:

Simple: 344,343,344,359,343,359,344,359,359,359

Average: 351.30 ms.

Optimized: 281,297,297,297,297,281,281,297,281,281

Average: 289.00 ms

Reverse do/while: 391,407,391,391,500,407,407,406,406,406

Average: 411.20 ms.

FireFox 3.0.1:

Results:

Simple: 278,251,259,245,243,242,259,246,247,256

Average: 252.60 ms.

Optimized: 267,222,223,226,223,230,221,231,224,230

Average: 229.70 ms.

Reverse do/while: 414,381,389,383,388,389,381,387,400,379

Average: 389.10 ms.

roenving
A: 

I think you have two alternatives. For dom elements such as jQuery and like frameworks give you a good method of iteration. The second approach is the for loop.

David Robbins