75

These are mainly just some things I've been wondering, maybe someone can give me a little more insight on them, i'll share what i've noticed so far as well!

First thing i've been wondering... is there any difference good or reason to use:

$('element').each(function (i, el) { });

-- versus --

$.each($('element'), function (i, el) { });

Looking at the jQuery docs I can't see any rhyme or reason for one or the other (maybe you know an instance or additional things one can do over the other.

But more importantly I'm concerned with speed here

// As opposed to $.each() looping through a jQuery object
// -- 8x faster 
for (var i = 0, $('.whatever').length; i < len; i++) {
    $('.whatever')[i] // do stuff
}

If you check out this jsFiddle DEMO here, you'll see the difference in speed is basically equivalent with either of them, but more importantly I feel like I should always be using for() loops...

I was just unit testing (looping through each of 5 different scenario functions, 50,000 times), simply looping through a bunch of list items, and setting a data-newAttr, nothing special.


QUESTION :: I guess my biggest question is, why not always use for loops while iterating through an object?? Is there even a point to using $.each()? Do you always use for() loops even when going through jQuery objects?

jsFiddle DEMO here

Function type:                  Execution Time:
_testArea.each() + $(this)               1947   <-- using $(this) slows it down tremendously
$.each()         + $(this)               1940
_testArea.each() + el(plain JS)           458   <-- using the Element speeds things up
$.each()         + el(plain JS)           452
for() loop       + plainJS[0] iteration   236   <-- over 8x faster

Just my 2cents. :)

Mark Pieszak - Trilon.io
  • 61,391
  • 14
  • 82
  • 96
  • 31
    As Joe Armstrong once wrote in response to a similar question on the Erlang mailing list, "Just write the most beautiful program you can." Let performance problems come to you. Will you really be working on pages that iterate 50,000 times? If yes, then by all means optimize. – Pointy Aug 09 '12 at 16:08
  • 3
    What would a `for` loop iterating over jQuery DOM elements look like? – Jordan Aug 09 '12 at 16:09
  • @Jordan I would guess about 1730ms .. give or take a hundred :) [As Jordan points out, these micros are *not* correctly testing the "8x" stated; they only show it is "2x" faster in that case.] –  Aug 09 '12 at 16:09
  • 2
    Test it for yourself on jsperf.com – j08691 Aug 09 '12 at 16:11
  • 1
    Always, Javascript functions will be faster then a Jquery Function because javascript is native, but i think tht the point of use the each instead of for, it's make the code faster using the framework, and the advantages – Jorge Aug 09 '12 at 16:13
  • 1
    Considering that jQuery.each *uses* `for` internally then it *must* do more work overall .. according to these figures, "about 2x as much" in this particular case/implementation. As more work is done inside the loop *the total difference will decrease*. (Please consider using http://jsperf.com for micro-benchmark. It is designed for this.) –  Aug 09 '12 at 16:16
  • 5
    The `.each()` method iterates over jQuery objects. The `$.each()` static method can iterate over various types of objects, like plain objects, arrays, and array-like objects. That's the difference. – Šime Vidas Aug 09 '12 at 16:17
  • Your question looks like 3 questions in one. 1) different formulations of jQuery.each, 2) Should I optimize my code for perforance? 3) What is the speed of different interation techniques. See the link for answers of 2 http://stackoverflow.com/questions/183201/should-a-developer-aim-for-readability-or-performance-first – Aaron Kurtzhals Aug 09 '12 at 16:18
  • 1
    Why use jQuery and not directly the DOM API? It's way faster! `;)` – Felix Kling Aug 09 '12 at 16:23
  • @ŠimeVidas That is a negligible (as in, 0 ms) constant overhead: not an overhead per iteration though. Arrays are still iterated as expected (see http://code.jquery.com/jquery-latest.js). The overhead per iteration would include the function calls, index incrementing, and "break" checking. –  Aug 09 '12 at 16:24

6 Answers6

49

One thing that .each() allows you to do that can't be done with a for loop is chaining.

$('.rows').each(function(i, el) {
    // do something with ALL the rows
}).filter('.even').each(function(i, el) {
    // do something with the even rows
});

I played around with your JSFiddle to see how chaining would influence performance in cases where you have to loop through subsets of the original set of matched elements.

The result wasn't all that unexpected, although I think the overhead of end() was exaggerated here because of the combination of few elements and many loops. Other than that: plain JS loops are still slightly faster, but whether that weighs up to the added readability of .each() (and chaining) is debatable.

  • Wow! Thank you, didn't even think about chaining like this, that's definitely a big benefit itself! It's so much more code to do in plain JS and once you have a bunch of if/else things happening to accomplish the same thing, the ms benefit is pretty much non existent. – Mark Pieszak - Trilon.io Aug 09 '12 at 17:34
  • 1
    inperformant! I would filter inside the outer each() just because each().filter() would process same array twice, its less convinient but more performant. And if you expect a big number of elements then I would abstain from using each() iteration at all, just take a look at http://jsperf.com/function-call-overhead-test regarding function call overhead – comeGetSome Apr 25 '13 at 14:28
22

One thing you do get with .each() is automatic local scoping (because you are invoking an anonymous function for every object), which in turn means if you are creating even more anonymous functions/closures/event handlers/whatever on every iteration, you never have to worry about your handlers sharing a variable. That is, JavaScript doesn't act like other languages when it comes to local scopes, but because you can declare a variable anywhere, it can fool you sometimes.

In other words, this is wrong:

var idx,el;
for (idx = 0; idx <someObjectArray.length; idx++){
   el = someObjectArray[idx]
   el.someEventHandler(function(){  
       alert( "this is element " + idx);
   }); 
}

Whenever any of those objects invoke their "someEvent" after this loop (please note that this is made up), the alert is always going to say whatever was last assigned to idx, which should be (as of the time invoked) someObjectArray.length;

To make sure you save the proper index, you have to declare a local scope, create a variable and assign to that variable for use.

var idx,el;
for (idx = 0; idx <someObjectArray.length; idx++){
   el = someObjectArray[idx];
   (function(){
       var localidx = idx;
       el.someEventHandler(function(){  
           alert( "this is element " + localidx);
       }); 
   })();
}

As you can see, that's as ugly as hell, but it should work. Each event handler gets its own copy of localidx

Now compare that to .each()

$(someObjectArray).each(function (idx, el) { 
   el.someEventHandler(function(){  
       alert( "this is element " + idx);
   }); 
});

A lot simpler, isn't it?

JayC
  • 7,053
  • 2
  • 25
  • 41
  • 1
    Very true! I actually forgot for a second it already does this for you... I suppose the biggest thing to take from it all is that if you want simple manipulation | get/set type things an easy for() w plain JS is really the way to go. For much more complicated filtering & eventHandlers you almost need each(). Interesting... – Mark Pieszak - Trilon.io Aug 09 '12 at 18:25
9

jQuery.each vs for-loop

Advantages jQuery.each:

  • Fits well in jQuery code (chaining and style).
  • No worries about scope (references to the iterator and object will be persistent).
  • Can be used universally (for all kinds of objects and iterating over object keys).

Advantages for-loop:

  • High performance (for games/animations/large datasets).
  • Full control over iterator (skip items, splice items from list, etc).
  • The for-loop will always work, for there is no dependency on jQuery.
  • Same familiar syntax as most other similar languages.

Example code

This is example code of how I prefer to iterate over a list.

var list = ['a', 'b', 'c', 'd', 'e', 'f'];

jQuery.each:

$.each(list, function(i, v)
{
    // code...
});

For-loop without closure:

for(var i=0,v,n=list.length;i<n;i+=1)
{
    v = list[i];
    // code...
}

For-loop with closure:

for(var i=0,n=list.length;i<n;i+=1)
{
    (function(i, v)
    {
        // code...
    })(i, list[i]);
}

Note: I suggest you just use the standard for-loop, and only use a closure when necessary. However, when your code looks more like jQuery than Javascript anyway, it could be easier to just use $.each. In case of performance issues, you could always look into it afterwards.

Yeti
  • 2,647
  • 2
  • 33
  • 37
5

I ran some simple performance test while ago http://jsperf.com/forloops3. Seems that sticking to plain, old for loop (where it's possible) is the way to go :)

op1ekun
  • 1,918
  • 19
  • 26
4

When I went to your link here are two numbers I got:

$.each() + el(plain JS) 401
for() loop + plainJS[0] iteration   377

If the difference is that small, then go with the one that is most readable, but, if you have very high time requirements, then you may just need to go with what ends up being the fastest.

I would suggest you write your program to use three different methods, the two above, and then use the foreach found in newer versions of javascript, and for those browsers that don't support it you can add it as a prototype.

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach

You know what your requirements are, and what your program will do, so just write your own tests and ensure it meets the requirements across at the browsers you will be supporting.

For your first question, I would go with $('element').each as it is much easier to read, but that just my opinion.

James Black
  • 41,583
  • 10
  • 86
  • 166
  • 2
    Although for such small margins it likely *doesn't make a [rhymes with spam] bit of difference* .. I would just use the "more clear consistent version" (whichever that is determined to be) unless there was a *specific* real-world performance case indicating it was too slow. –  Aug 09 '12 at 16:19
  • 1
    @pst - The small margin can make a difference if you call it 10000 times and this small difference puts you outside your allowed window, which is what I was asking about, and the only way to truly know is to test on various browsers with the three versions and get some numbers. – James Black Aug 09 '12 at 16:35
  • Thank you James! Yes in my case it's definitely an issue, we need to support legacy browsers, but now I see that **readability & chainability - wise** - it makes sense to use `each()`, and afterwards stick with straight plain JS! The difference really is non existent, it seems that unless I need it to remain a JS object, I don't need to use `$(this)`. – Mark Pieszak - Trilon.io Aug 09 '12 at 17:40
2

Actually there is a big difference between $.each() and $().each().

They do slightly different things depending on what you're passing in.

http://api.jquery.com/each/ vs http://api.jquery.com/jquery.each/

jquery.each is a generic iterator, where $().each() is specific to a jquery collection.

Also see: http://jsperf.com/each-vs-each-vs-for-in/9

ryanneufeld
  • 157
  • 1
  • 4
  • You can just as easily use both the same way: `$(['someItem', 'anotherItem']).each(function (i, el) { });` http://jsfiddle.net/zzVQD/. Also this doesn't mean the question deserves a downvote, I put plenty of research / code / effort in it. – Mark Pieszak - Trilon.io Oct 24 '13 at 15:31
  • 1
    though this isn't an answer for this question, it adds some knowledge. – Swaps Sep 27 '18 at 09:53