📜 ⬆️ ⬇️

Use quick selectors for jQuery

As you know, in the development of a bulk JS application where the most popular jQuery library is used, there comes a moment when the performance problem is acute. All forces rush to the profiler embrasure, each challenge is scrupulously investigated, each functionally loaded piece of realization is sniffed from all sides and straightened. But the trouble comes from the wrong side, where it is waiting for 90% of developers. Selectors - How much is in this word.
Let's see how this magic works and why searching for DOM elements can cause a drop in application performance.

How jQuery parses the selector


The library itself uses the Sizzle engine to search for items, which has a number of features. We will consider them.

querySelectorAll ()

The new browsers have the excellent querySelectorAll () and querySelector () functions, which can search for items using the browser's capabilities (in particular, used when viewing CSS and assigning properties to elements). This feature does not work in all browsers, but only in FF 3.1+ , IE8 + (only in standard IE8 mode) , Opera 9.5+ (?) And Safari 3.1+ . So Sizzle always determines the presence of this function and tries to perform any search through it. However, this is not without surprises — to successfully use querySelectorAll (), our selector must be valid.
I will give a simple example:
The two selectors are almost the same and will return the same set of elements. However, the first selector will return the result of querySelectorAll (), and the second will return the result of normal filtering by elements.
$('#my_form input[type="hidden"]')
$('#my_form input[type=hidden]')

Parse selector and search

If querySelectorAll () was not used, Sizzle will try to use the usual browser functions getElementById (), getElementsByName (), getElementsByTagName () and getElementByClass (). In most cases, they are enough, but (sic!) In IE <9 getElementByClassName () is broken and using a class selector will result in a complete search of elements in this browser.
In general, Sizzle parses the selector from right to left. To illustrate this feature, here are some examples:
$('.divs .my_class')
First, the .my_class elements will be found, and then only those that have .divs in the parents are filtered out. As we can see, this is a rather expensive operation, and the use of context does not solve the problem (we will talk about the context below).
As I said, in most cases Sizzle will parse the selector from right to left, but not in the case of using an element with an ID:
$('#divs .my_class')
In this case, the selector will behave as expected and the #divs element will immediately be taken for use as a context.

Context

The second parameter passed with the selector to the $ () function is called the context. It is intended to narrow the search for items. However, when parsing, the context will dock to the top of the selector, which does not give any gain at all. The winning combination of context usage is a valid selector for querySelectorAll (), since this function can be applied not only on behalf of the document, but also from the element. Then the selector with context figuratively transforms the following construction:
$('.divs', document.getElementById('wrapper'));
document.getElementById('wrapper').querySelectorAll('.divs'); // querySelectorAll()

In this example, if querySelectorAll () cannot be used, Sizzle will filter the elements by a simple search.
One more note about context (it's not about selectors) - if the second parameter to the selector for the .live () function is to pass a jQuery object - the event will be caught on document (!), And if the DOM object - then the event will pop up only before this element . I try not to memorize such subtleties, but use .delegate () .
')
Filters and element hierarchy

To search for nested items, you can use the following selector:
$('.root > .child')
As we know, the selection of the selector and the search will start from all .child elements on the page (provided that the querySelectorAll () is not available). Such an operation is quite expensive and we can transform the selector like this:
$('.child', $('.root')[0]); //
$('.root').find('.child'); // .root?
$('.root').children('.child'); //

However, if there is a need to use filters for any attributes (: visible,: eq, etc.) and the selector looks like this:
$('.some_images:visible')
then the filter will be applied last - i.e. we are again retreating from the right-to-left rule.

Results


Quick selectors to you in the new year! All in the coming!

Based on the workshop of Ilya Kantor and his own observations.

Source: https://habr.com/ru/post/111195/


All Articles