Scroll down for the getById.getByClassName
vs. qSA
comparison!
If we wanted to select all elements of class "bar"
which are inside the element with the ID "foo"
, we could write this:
$( '#foo .bar' )
or this:
$( '.bar', '#foo' )
There are of course other methods to achieve this, but for the sake of this question, let's compare only these two methods.
So, which of the above methods performs better? (Which needs less time to execute?)
I have written this performance test:
(function() {
var i;
console.time('test1');
for( i = 0; i < 100; i++ ) {
$('#question-mini-list .tags');
}
console.timeEnd('test1');
console.time('test2');
for( i = 0; i < 100; i++ ) {
$('.tags', '#question-mini-list');
}
console.timeEnd('test2');
})();
You have to execute it from within the console on the Stack Overflow start-page . My results are:
Firefox:
test1: ~90ms
test2: ~18ms
Chrome:
test1: ~65ms
test2: ~30ms
Opera:
test1: ~50ms
test2: ~100ms
So in Firefox and Chrome, the second method is multiple times faster - just as I expected. However, in Opera the situation is reversed. I wonder what's going on here.
Could you please run the test on your machine and explain why Opera performs differently?
Update
I've written this test, in order to investigate whether Opera's qSA really is super-fast. As it turns out, it is.
(function() {
var i, limit = 5000, test1 = 'test1', test2 = 'test2';
console.time( test1 );
for( i = 0; i < limit; i += 1 ) {
document.getElementById( 'question-mini-list' ).getElementsByClassName( 'tags' );
}
console.timeEnd( test1 );
console.time( test2 );
for( i = 0; i < limit; i += 1 ) {
document.querySelectorAll( '#question-mini-list .tags' );
}
console.timeEnd( test2 );
})();
Again, you have to run this code from within the console on the Stack Overflow start-page. I used the Firebug Lite bookmarklet for IE9 (since that browser doesn't implement console.time
).
So, I compared this method:
document.getelementById( 'A' ).getElementsByClassName( 'B' );
to this method:
document.querySelectorAll( '#A .B' );
I've executed the above script five consecutive times in each browser. The arithmetic means are:
(All numbers are in milliseconds.)
So, the performance of the first method is pretty much the same in the tested browsers (16-36ms). However, while qSA is much slower compared to the first method, in Opera it actually is faster!
So, qSA optimization is possible, I wonder what the other browsers are waiting for...
Source: Tips4all
jQuery/Sizzle will avoid using the JavaScript based Sizzle engine if the browser supports querySelectorAll, and if you pass a valid selector (no custom, non-CSS selectors).
ReplyDeleteThis means that you're ultimately comparing implementations of querySelectorAll, assuming you're testing browsers that support it.
There are other optimizations that jQuery or Sizzle uses, so it's tricky when comparing different types of DOM selection in different browsers.
The reason for Opera's performance result seems to be that they have a very highly optimized querySelectorAll implementation. qSA, being a relatively new method, hasn't been quite as optimized in some browsers compared to older methods like getElementsByTagName.
For reference, this is 30x faster:
ReplyDeletedocument.getElementById("foo").getElementsByClassName("bar");
See jsPerf: http://jsperf.com/jquery-selector-variations/3. This would need a shim to work in older versions of IE.
While jQuery is extremely useful, if speed is of the utmost, it's not always the best tool for the job.
And the winner is....
ReplyDeletetest 3 $('#question-mini-list').find('.tags');
test1: 25ms
test2: 19ms
test3: 10ms
The two methods you suggested are not equivalent.
test 1: Sizzle parses from right to left (don't ask it to search ever element on the page, then restrict to an ID).
test 2: Using a string as a context is generally of no use, use elements as a context.
test 3: Finding elements with an id is blazingly fast. Once you're there it's a breeze to focus in on an item of a given class.