Synopsis
Use #ID selector wherever possible. It is the fastest.
Ensure slower selectors are optimised for performance – Combine them with faster selectors where possible.
Custom selectors must be kept simple, as they may end up being run upon every element in the DOM.
Avoid needless selector combinations.
Description
Selectors are ranked by performance as follows:
- #Id
- Element
- .class, :pseudoclass and :custom
The Class and PseudoClass and Custom selectors are slower than ID and Element selectors. The deficiency of their performance can be mitigated by combining them with other selector types, so do this wherever possible.
Examples
$(".oddRows"); //Inefficient: scans DOM for all elements with oddrows class $("tr.oddRows"); //More efficient: Searches only <tr>s with oddrows class $("#MyTable tr.oddRows"); //More efficient: searches descendents of #MyTable $("#MyTable>tbody>tr.oddRows"); //Best: searches immediate children
In these examples, we have combined CSS style selectors to obtain better performance in two ways:
- Element.WithClass – I.e. search for element with the specified class name
- #Id Descendents – I.e. search within descendents of the Id.
- #Id>Children – I.e. search only immediate children
The optimisation of selector performance is essential for efficient jQuery. This must be a major consideration for developers and code-reviewers alike.
Custom Selectors
It is possible within jQuery to define custom selectors, as per the following example:
$.extend($.expr[":"], { textboxEmpty: function(el) { return $(el).val() === ""; //must return boolean }});alert($(":text:textboxEmpty").length);
Custom selectors must be kept simple, as they may end up being run upon every element in the DOM.
Be aware that Custom and Pseudoclass selectors are, at best, as slow as class selectors (complex custom selectors may be even be slower!). Therefore you should attempt to optimise their performance by utilising some of the techniques described above.
For a tutorial on writing custom selectors, check out my blog post here.
Pitfalls and Traps
Assuming Children and Descendants
The example “#MyTable>tbody>tr.oddRows” helps us demonstrates the potential pitfalls of assuming specific children/descendants. Had we written this as “#MyTable>tr.oddRows” then our selector would have returned nothing!
Correct Use of Parent-Child
The selector $(“#MyTable .oddRows”) will return all elements in the DOM with the oddrows class assigned (there is a space between #MyTable and .oddRows)
However, the selector $(“#MyTable.oddRows”) will probably return nothing, as the code imples that we are looking for the table with the Id #MyTable that has the class oddrows assigned to it.
Given the naming convention in the example it seems unlikely that that the table will have the class assigned.
Needless Selector Combinations
The Id of an element should be unique. Therefore there is no need to combine it with other selectors. For example, the selector $(“#MyTable.TableClass”) is probably pointless as the query for #MyTable will already have returned at most one element.
In the same vein, the selector $(“div #MyTable”) is also pointless. Here we are going to select all divs in the DOM, and then scan that subsection for #MyTable.
Defining an Id at the start of a Parent-Child selector can, however improve selector performance greatly, and is strongly encouraged. See selector performance examples above.
jQuery Coding Standards Menu
[...] Selectors [...]
[...] Selectors [...]
nice write up, thanks for sharing. personally I was not aware of the performance differences with selectors you pointed out!
besides that…
“Correct Use of Parent-Child
The selector $(“#MyTable .oddRows”) will return all elements in the DOM with the oddrows class assigned (there is a space between #MyTable and .oddRows)”
should probably read something like…
“…The selector $(“#MyTable .oddRows”) will return all elements in the DOM inside the #MyTable element…” or something similar.
…or am I missing a point here?
Cheers
k.