开发者

jQuery optimization selector

I was wondering the other day when typing you selectors in jQuery would it make a difference in performance if you specify your selectors very specific or very loosely.

E.g

$('$myId .someElement')

Or

开发者_开发问答$('table#myId > tbody > tr > td > div.someElement');

Would the 2nd option be a lot quicker or would the difference be neglectable, say when doing .each() if you need to find the same element over and over.


Update 2:

To sum up some other comments here. The answer is it depends.

jQuery's selector engine Sizzle evaluates the selector the same way CSS does: from right to left. So in general it is better to be very specific on the right side and less specific on the left side.

But it also depends on the structure of the HTML and how scattered the elements are that you want find.

So if you have

                         a
                         |
                        ...
                         |
                         b
                 -----------------
                 |               |
d d d c c c c c   c c c c c c c c   c c c c c c

then being more specific is faster $('a b > c'), because you are reducing the element set early with b > c and don't have to check the a inheritance for every c.

Whereas if you have

                         a
                         |
                        ...
                         |
                         b
                 -----------------
                 |               |
e e e e e e e e   d d c c c c c c   e e e e e e

then $('a c') would be faster, since the selector is simpler and testing c for being a child of b is redundant in this case (of course you could even do $('c')).


Original answer:

Regardless which one of them is faster, if you have to access an element over and over again, store a reference to it:

var $element = $('#myId .someElement');

$('some other selector').each(function() {
    // access $element here
});

The first selector seems to be a bit faster (in Chrome 8).

In newer browsers (that support querySelectorAll), the difference is probably not as big as in browsers that do not support it.

Update:

I think it mostly depends on how many built-in methods jQuery can use. So assuming querySelector* is not available, the first selector can be translated to

document.getElementById('myId')[0].getElementsByClassName('someElement')

For the second selector, jQuery would have to additionally check whether an element is indeed a child or not. I.e. there is some more processing involved.


I would go for:

$('.someElement', '#myId')

Since getElementById is the fastest selector operation, you are first filtering your content and then searching for the class. Also the fewer the selectors the faster the selections will be (depends if using descendant or child selectors - check comments!) . Test based on @Felix test case.

Edit: so to enhance this answer. Based on the jQuery documentation:

By default, selectors perform their searches within the DOM starting at the document root. However, an alternate context can be given for the search by using the optional second parameter to the $() function.

So when you provide a second parameter (a context), jQuery will search for that element first and then search within it, so it would be translated from:

$('.someElement', '#myId')

To:

$('#myId').find('.someElement')

Now the trick is, trying to find the closest container of your element that actually holds an ID and put it as context, since ID selection is the fastest. Now you would say, why not then using the second already translated one, by I wouldn't actually care that much since the first is cleaner and it's not much slower:

                    $('.someElement', '#myId')                  $('#myId').find('.someElement')
Chrome 8.0.552              36,527                                      37,400
Firefox 3.6.13              17,632                                      19,155


'#myid .myclass'

1) find all elements that have the class myclass
2) for each such element, go up its ancestor chain and stop if you get to the #myid ancestor. If there is no such ancestor, discard the element.

Now, it could very well be that browsers optimize this process, for example:

1) find the #myid element
2) find all elements that have the class myclass and that are descendants of the #myid element


table#myid > tbody > tr > td > div.mylcass

Note that prefixing the ID selector with a type selector has no effect, since IDs are unique in the document.

#myid > tbody > tr > td > div.mylcass

Prefixing a class selector with a type selector is performance-wise better. So, if you know the type of the element, you are encouraged to set it.

I'm not sure about those child selectors. I guess it should be faster if you use them. But how much faster? Possibly neglectable? Also, It looks ugly.

Consider this:

#myid td > div.myclass 

If #myid is a table element, and you have no nested tables, then this selector should be as fast as your second selector. I'd use this one.


The second one will be faster, since it knows exactly what to look for at each step.

In this example:

$('table#myId > tbody > tr > td > div.someElement');

If there were no tbody, or no tr, or no td (etc), it could shortcut out of the search straight away. Also, every subsequent step will narrow down the search (eg: not searching inside the <thead>). Compare to this example:

$('#myId .someElement')

This would have to scan every sub-element of #myId.


Edit: As FelixKing pointed out, your first example $('#myId .someElement') is actually faster. Only marginally, but still, faster, so I thought I should respond. Using the child selector (>), as opposed to the descendant selector (a space) is the fastest traversal method, since the possible set of elements is much less. However, modern browsers have highly optimised built-in methods which jQuery can sometimes make use of, actually reducing the execution time. So, as seen in this particular case, the 'worse' one is actually better, since the browsers are better optimised for executing that particular query. In general however, the original point still stands, particularly if you're using something which couldn't possibly be optimised by browsers (custom selectors, for example).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜