jQuery performance: Avoid the each() method

jQuery performance is a huge an well discussed topic on the web with many opinions and arguments and this post is absolutely not about criticizing this fantastic library that helps us web developers every day, but showing that it also has some downsides and potential bottlenecks you should know about.

One thing would be: When it comes to iteration the native way is absolutely the best. Why?

The experiment

Think of the following simple example:

var i;
var count = 60000;
var parent = document.getElementById('container');
var fragment = document.createDocumentFragment();
var clear = document.createElement('div');
clear.style.clear = 'both';
 
for(i=0; i<count ; i++) {
	var color = 'rgb('+ parseInt((Math.random()*255)) + 
                    ',' + parseInt((Math.random()*255)) + 
                    ',' + parseInt((Math.random()*255)) + ')';
	var item = document.createElement('div');
	item.className = 'item';
	item.style.width = '2px';
	item.style.height = '2px';
	item.style.backgroundColor = color;
	item.style.float = 'left';
	fragment.appendChild(item);
}
 
parent.appendChild(fragment);
parent.appendChild(clear);

Here, we add 60.000 left floated div items with a random color to a container in the HTML document and an item to clear. On old machines this alone could be heavy, but what if we want to change the color of each item again after we added them to the DOM?

With jQuery you would do it like this:

$('.item').each(function() {
    var color = 'rgb('+ parseInt((Math.random()*255)) + 
                ',' + parseInt((Math.random()*255)) + 
                ',' + parseInt((Math.random()*255)) + ')';
    $(this).css('background', color);
});

In Chrome 30 on my machine this takes about 2.80 seconds to load it locally with a HTML document that only contains the container div element, the jQuery library and some styles with it in the header.

Now, let’s do it the native way. For that I will use the method querySelectorAll() of the document object to fetch all div elements with the class item – yeah, I know it’s not IE7 compatible, but I don’t care for this old browser anymore (no one should).

It would look like this:

var items = document.querySelectorAll('div.item');
for(i=0; i<count ; i++) {
    var color = 'rgb('+ parseInt((Math.random()*255)) + 
                ',' + parseInt((Math.random()*255)) + 
                ',' + parseInt((Math.random()*255)) + ')';
    items[i].style.background = color;
}

This would load up in about 2 seconds (~1s less) with the same conditions and the same machine as above.

You could argue now, that this is not that much of a difference, but think of a larger and more complex document with more javascript executed and more stuff done, where you not only load this potion of script – it could make a difference.

But why is jQuery so much slower when it comes to iteration?

The simple answer would be: Because you load up some functional iteration.
The longer one: When executing the each() function of jQuery, javascript needs to create a new scope for every iteration made, because you always fire up an anonymous function. This includes all local variables, all global ones and the other stuff which needs to be loaded again and again.
With the native way you only loop through objects and set the color and the querySelectorAll() method itself is native to the browser and needs no library to load, so it’s faster executed.

Conclusion

If you can, avoid using each() iterations and this includes all other libraries with this kind of iteration methods (e.g. prototype, etc.), too. The native way may look old school at first glance, but you’ll may see some performance boost not doing it the “modern way”. Use jQuery where it is useful and avoid it, where you can do it better natively.

Similar Posts: