jQuery: Performance analysis of selectors

In this article jQuery is tested with different selectors in order to find specific elements in the DOM tree. The delay of each selector is precisely calculated and the idea is to find out which one is the fastest for the given goal.
08-Dec-2007 16:01 GMT

jQuery is one of the best javascript libraries I have ever worked with. It is quite simple and usually reduces the amount of javascript code in web applications. Besides all the advantages it brings to the web community, we have to pay attention to a few details when reusing this library in order to get the best part of it.

I will describe a few tips on how to improve the performance of your javascript code. Most of these tips aren't a big deal if your pages are small and simple. But if you create complex html pages, you should follow them in order to prevent the browser from locking when the page loads up. Even if you are not concerned with performance at all, learning these things will bring benefits to your overall knowledge about this library.

jQuery has a bunch of different selectors - as you can see from the documentation here - and I won't consider all of them in this analysis. My idea is to explore different ways of finding a specific element in the html page by using different types of search. Benjamin Sterling has already researched this topic here, but I want to add a different point of view, which is more accurate and provides more alternatives for the developers.

Let me start talking about the test html page, which has over 20,000 elements separated in chuncks of 5,000. Basically, there are 5,000 <div> + 5,000 <span> + 5,000 <p> and 5,000 <small> with the following characteristics:

<!-- 5000 'div' elements -->
<div id="a-0" class="div-0" row="a-0">Div 0</div>
<div id="a-1" class="div-1" row="a-1">Div 1</div>
...
<div id="a-4999" class="div-4999" row="a-4999">Div 4999</div>


<!-- 5000 'span' elements -->
<span id="b-0" class="span-0" row="b-0">Span 0</span>
<span id="b-1" class="span-1" row="b-1">Span 1</span>
...
<span id="b-4999" class="span-4999" row="b-4999">Span 4999</span>


<!-- 5000 'p' elements -->
<p id="c-0" class="p-0" row="c-0">Paragraph 0</p>
<p id="c-1" class="p-1" row="c-1">Paragraph 1</p>
...
<p id="c-4999" class="p-4999" row="c-4999">Paragraph 4999</p>


<!-- 5000 'small' elements -->
<small id="d-0" class="small-0" row="d-0">Small 0</small>
<small id="d-1" class="small-1" row="d-1">Small 1</small>
...
<small id="d-4999" class="small-4999" row="d-4999">Small 4999</small>

The 20,000 elements above are generated by javascript. They provide a good laboratory to check the speed of each selector, since we can expect more accurate results in this analysis. The page itself has a few more tags to display information and execute each test, but this shouldn't affect the final results.

The test page is available here. It takes a few seconds to load because the javascript must create the DOM tree as described above. So please be patient. Note also that each test uses the measure() function, which calculates the delay of the call in milliseconds.

Test 1 - Finding an element by ID

The first test is to find an element by its ID. I decided to get the element whose ID is "d-2642". We can do this in three different ways:

A - Using the ID selector

$('#d-2642').html()

B - Using attribute search

$('[id="d-2642"]').html()

C - Using attribute search + tag

$('small[id="d-2642"]').html()

Running this test for the first time in different browsers, I could reach the results displayed in the following table (in milliseconds). It is clear that the # operator is the most efficient one.

Firefox Opera IE6 IE7 Safari
A 156 0 31 40 0
B 3609 828 2344 841 844
C 578 93 406 210 172

Test 2 - Finding an element by Class

Although CSS classes are intended to be reused among elements, you might create some elements with a unique class name just to identify and retrieve them through javascript. This is exactly what we test in this second test by seaching the element whose class is "p-4781". We have four alternatives:

A - Using the class selector

$('.p-4781').html()

B - Using the class selector + tag

$('p.p-4781').html()

C - Using attribute search + tag

$('p[class="p-4781"]').html()

D - Using tag search + filter

$('p').filter('.p-4781').html()

After running this test for the first time in different browsers, I got:

Firefox Opera IE6 IE7 Safari
A 2891 641 1718 631 329
B 453 78 313 180 78
C 422 109 578 201 187
D 203 266 375 210 94

The table above shows case B as the fastest selector for most browsers (except Firefox). It is easy to understand why case A isn't efficient, since the code has to iterate over all elements of the DOM tree. Case C and D aren't that bad, but I would say case B should be the preferred one for this goal.

Test 3 - Finding an element by Attribute

The third test is to find elements by a given attribute value. Sometimes this technique is useful and I decided to test it by searching for the element that has "c-3221" as the value of the row attribute. There are four possibilities in this case:

A - Using attribute search

$('[row="c-3221"]').html()

B - Using attribute search + tag

$('p[row="c-3221"]').html()

C - Using tag search + filter

$('p').filter('[row="c-3221"]').html()

D - Using (tag + attribute) search + filter

$('p[@row]').filter('[row="c-3221"]').html()

Running this test for the first time in different browsers, I could get the following results:

Firefox Opera IE6 IE7 Safari
A 6610 1390 2500 801 1156
B 1250 360 406 200 250
C 1265 968 485 231 281
D 4078 1000 656 320 625

Case B is for sure the best approach to find an element by a specific attribute value.

Conclusions

This experiment was an attempt to find the right and fastest way of finding specific elements in the DOM tree using jQuery. Every jQuery developer should know and understand these details in order to create efficient code. Benjamin Sterling gave the first step in such performance analysis, but I could provide another point of view, which uses a big DOM tree and more alternatives to be checked.



Stumble it!      Dzone.com      Digg.com      Reddit.com      Del.icio.us

Comments

Total: 9 comments
Benjamin Sterling
08-Dec-2007 16:42 GMT
This is good approach, I would argue that not more accurate, you just took a different approach to saying the same thing. You just say it much better than I can.

Also, $('p[@row]') should be $('p[row]'), the @ at depreciated in 1.2, it can be still used, but I think they will be getting rid of it all together in the next release, which should be sometime this month (I can't find the email that verified the date).

Over all, really nice post. I am going to bookmark so I can refer back to it.
Hugo Teixeira
08-Dec-2007 16:48 GMT
@Benjamin
Thank you for your opinion and feedback.
As I said, this is just a complement for your nice work. :-)
I didn't know about the issue with the @ operator -- this is why I didn't find documentation about it in the official website (only in my books). :-))

Let's keep up the good work!
Kevin Smith
10-Jun-2008 14:46 GMT
Thank you for this article. It helped me troubleshoot a jQuery performance issue I was experience and am now running smoothly again!
Dusan Kmet
20-Apr-2009 13:04 GMT
Nice testing, ... but if i need selector in few functions, what is better?
1. define new var a this var use in function
var $inputs = $("#mform input");
function a1(){ $inputs... }
...
function a10(){ $inputs... }

2. or in each function call new selector
function a1(){ $("input")... }
...
function a10(){ $("input")... }
Adam Schwartz
30-Apr-2009 20:31 GMT
@Dusan
Creating a reference to $('#mform input') will increase performance because jQuery is only called once. However, the trade-off is that you'll have more global variables, and more objects stored in memory. For something like $('#id'), I'd recommend calling it every time, since the native document.getElementById('id') will be used. However, if out of necessity, you must call $('.className') in every function, I might recommend assigning it to a variable, since the jQuery call for a class will be much slower.
ghghgh
07-Jul-2009 11:58 GMT
fghgh
Robin Jakobsson
18-Sep-2009 14:56 GMT
Thank you for this test, very useful and interesting!
vilo
27-Mar-2010 07:31 GMT
Could you please provide information on browser versions and the CPU the tests were done on?

And in the test 2 case C works only if there is only single style class defined. If there are more (separated by space), attribute test would not match them.

Eric Steinborn
29-Apr-2010 14:53 GMT
jQuery 1.4.2 changes all the values from these tests dramatically, but the results are still proven to be the same

Name

Enter your full name.

Your Comment

Please keep your comment relevant to the subject of the story.
HTML tags are not allowed. Use [b] and [/b] for bold text.
29 + 6 =