And then, the issue of performance arose. Somebody said that attribute selectors are much slower than class selectors and we should avoid them. Of course this is correct, because class selectors are based on the native function getElementsByClassName. But the question still remained, about how much it would affect performance overall.
To test this, I got part of this website’s HTML. It is considered a bit small, but good enough for testing. The HTML consists of 106 nodes and the element we are going to have the selectors for is at 6-th level depth. I have put on the element an attribute: data-hook=”foo”, a class: .data-hook, and an id: #hook. To run the tests I used jsperf.com which is really an awesome tool. So, lets look at the result:
The results of course are like we expected, but the difference is really huge. Attribute selector is 10 times slower than class selector and 40(!!) times slower than the id selector. What amazed me though is how slow the tag selector is, even though there is a native function for it.
Out of curiosity, I decided to test against other browser. Namely Firefox, Internet Explorer 8 and the new Internet Explorer 10. The results were these:
Since this post isn’t about comparing browser speed, I’ll just go over quickly a few things to note. We can see that Firefox is about 2 times as slow as Chrome, and IE8 is about 10(!!) times. The weird thing comes with the new IE10. It has the same performance with Chrome for class selector, and is just a bit slower for the id selector. But it is almost 10 times as fast for the tag selector, which is really impressive. However, the attribute selector speed is really disappointing and even more disappointing is the fact there has been no improvement from IE8.
Ok, back to comparing selectors. These tests are OK but what happens if we don’t select from the root of the element? What happens if we use a fast selector, to “restrict” the scope of the running selectors? In this scenario, let’s suppose we restrict the selection withing the article, thus starting from #post-47 (which could be a very realistic scenario). Essentially, instead of running $(‘[data-hook="foo"]‘), we will run $(‘#post-47 [data-hook="foo"]‘). Let’s see what happens in Chrome:
Now that was disappointing Even the attribute selectors got slower. My guess is that this happened because it executes the most-right selector first and then still walks the tree upwards, trying to find the parent node. Which in our case is pretty useless too, since we have a unique node.
Now, one last test. What if we use the jQuery method find(). Let’s see what happened:
Much better! Essentially this way, the speed is tripled compared to our initial attribute selector! Tag name selector also got an impressive improvement too! Of course the id selector lost a lot of performance but that was a bit expected. Same for the class selector.
So, lets try to summarize a few things then
- - Attribute selectors are the worst performing selectors of all
- - Class selectors perform nicely on all browsers
- - jQuery’s find() outperforms the css selectors.