views:

369

answers:

1

I just noticed that adding context to the selector is much faster than refining your selector.

$('li',$('#bar')).append('bla');

Is twice as faster than:

$('#bar li').append('bla');

Is this generally true?

+7  A: 

adding context to the selector is much faster than refining your selector

This is true in the general case. With respect to your specific examples however it is not necessarily true for jQuery <= 1.2.6.

Up to and including jQuery 1.2.6 the selector engine worked in a "top down" (or "left to right") manner. Meaning that both your examples would operate like this (roughly):

var root = document.getElementById('bar');
return root.getElementsByTagName('li');

jQuery 1.3.x (ie, Sizzle, which jQuery embeds) introduced a "bottom up" (or "right to left") approach to querying the DOM. So $('#bar li') now becomes (roughly):

var results = [];
var elements = document.getElementsByTagName('li');
for(var i=0; i < elements.length; i++) {
    var element = elements[i];
    var parent = element.parentNode;
    while(parent) {
        if(parent.id == 'bar') {
            results.push(element)
            break;
        }
        parent = parent.parentNode;
    }
}
return results

There are benefits and downsides to both approaches. You found one of the downsides.

Edit: just found out from this discussion that Sizzle trunk now makes a special exemption of selectors where #id is first. It uses that as the root context, speeding things up a bit. This should diminish if not eliminate the speed differences you are seeing.

Crescent Fresh