views:

174

answers:

4

I just saw a video of Nicholas Zakas of Yahoo, at GoogleTalks talking about speeding up your website. One of the things he mentioned was doing loops in reverse order to skip one of two comparisons: for (i = len; i--;) {}

And he said to keep away from JS libraries implementations of for each. Just for fun I thought I'd try it out. Turns out he was wrong.

var array1 = new Array();
var array2 = new Array();
var start = 0;
var finished = 0;
start = (new Date).getTime();
$("#newDivTest").children().each(function(i){ 
 array1[i] = $(this).get(0).id;
});
finished = (new Date).getTime() - start;
alert(finished);

start = (new Date).getTime();
var len = $("#newDivTest").children().length;

for (i = len; i--;) {
 array2[i] = $(this).get(0).id;
}
finished = (new Date).getTime() - start;
alert(finished);

newDivTest holds 1000 empty divs with an id starting at "0" and going up to "999". Another note is that $(this).get(0).id is about 3 times faster than $(this).attr("id") for some reason, anyone know why?

For FF3.5, the results are "7" and "45", IE7 gives "30" and "45", Chrome2 gives "4" and "17", Opera10 gives "16" and "16", and lastly Safari4 gives "4" and "16".

So it seems the approach Nicholas is hardest against is actually the faster in almost all instances.

I'm not smart enough to know what's going on behind the scenes for jQuery's each()-method, but it must be doing something right...right?

+1  A: 

Aren't your tests doing different things?

In the second test this is not the same as the first one.

Greg
+7  A: 

One flaw in your setup is that your second test will not actually work. You wrote:

for (i = len; i--;) {
    array2[i] = $(this).get(0).id;
}

But this is not defined there, so the entire operation will fail. You'd have to do something like:

var children = $("#newDivTest").children();
for (i = children.length; i--;) {
    array2[i] = children.get(i).id;
}

And this gets at a more pressing issue than performance: although calls to something like jQuery's .each() function do result in added function calls (and the associated added overhead), they also tend to make it much easier to express what you want the code to do.

Quoting Michael Jackson: "The First Rule of Program Optimization: Don't do it. The Second Rule of Program Optimization (for experts only!): Don't do it yet."

VoteyDisciple
Can't believe I missed that...geez. Rewriting it, the second one actually does end up being faster. Thanks for pointing it out anyway (:
peirix
+1  A: 

Slightly off topic and not a direct answer to your main question but, jQuery's each method is implemented like so (jQuery 1.3.2)

jQuery.extend({

        /* ... Code taken out for brevity ... */

    // args is for internal usage only
    each: function( object, callback, args ) {
     var name, i = 0, length = object.length;

     if ( args ) {
      if ( length === undefined ) {
       for ( name in object )
        if ( callback.apply( object[ name ], args ) === false )
         break;
      } else
       for ( ; i < length; )
        if ( callback.apply( object[ i++ ], args ) === false )
         break;

     // A special, fast, case for the most common use of each
     } else {
      if ( length === undefined ) {
       for ( name in object )
        if ( callback.call( object[ name ], name, object[ name ] ) === false )
         break;
      } else
       for ( var value = object[0];
        i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
     }

     return object;
    }

        /* ... Code taken out for brevity ... */

        );

as you can see, a callback function is applied to each property of object. the jQuery object has a length property defined so will perform the following loop (generally, no args are supplied)

for ( var value = object[0]; i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}

in each iteration, the callback function will increase the scope chain length by 1, thus will take longer to resolve the reference to the object's property.

Russ Cam
+1  A: 

I notice that your question is "JS looping and populating array. Which is faster?", but your examples are actually testing the speed of various selectors of JQuery, right? You might be interested in checking out :http://mootools.net/slickspeed/

As for "JS looping and populating array. Which is faster?", see here : http://blogs.sun.com/greimer/resource/loop-test.html

Joshua
No, my example was only testing the speed of jQuery's `each()` vs. native JS `for (i=len;i--;){})`...
peirix