Как говорящие на английском языке, наши умы направлены на интерпретацию данных и текста слева направо. Однако, как выясняется, многие из современных механизмов выбора JavaScript ( jQuery , YUI 3 , NWMatcher ) и собственный querySelectorAll
анализируют строки выбора справа налево.
Важно отметить, что чаще всего вам не нужно слишком беспокоиться о производительности селектора — если ваши селекторы не противны. Sizzle jQuery невероятно быстр и любезен.
Пример
Рассмотрим следующий селектор:
1
|
$(‘.box p’);
|
Хотя некоторые — обычно более старые — механизмы выбора сначала будут запрашивать DOM для элемента с class
box
, а затем переходят к поиску любых p
тегов, которые являются дочерними, jQuery работает в обратном порядке. Он начинается с запроса DOM ко всем тегам абзаца на странице, а затем .box
родительские узлы и ищет .box
.
JSPerf
Мы можем использовать отличный сайт JsPerf.com, чтобы проверить это.
01
02
03
04
05
06
07
08
09
10
11
12
|
// The markup
<div id=»box»>
<p> Hello </p>
</div>
// The Test
//1 .
$(‘#box p’);
// 2.
$(‘#box’).find(‘p’);
|
Изображение выше показывает, что использование find()
или children()
происходит примерно на 20-30% быстрее, в зависимости от браузера.
Библиотека jQuery имеет оптимизацию, которая немедленно определит, был ли передан id
в объект jQuery ( $('#box')
). Если это так, ему не нужно использовать Sizzle; вместо этого он быстро передает селектор в getElementById
. И, конечно же, если браузер достаточно современный, то Sizzle возьмет на себя querySelectorAll.
С другой стороны, с помощью $('#box p')
jQuery необходимо проанализировать эту строку с помощью Sizzle API, что займет немного больше времени (хотя Sizzle действительно имеет оптимизацию для селекторов, начинающихся с id
). Именно поэтому также немного быстрее делать такие вещи, как $('.elems').first()
над $('.elems:first')
. Последний селектор нужно будет проанализировать.
Другой пример
Давайте рассмотрим другой пример:
1
|
$(‘#container > :disabled’);
|
Этот селектор кажется подходящим. Найдите все отключенные входы (или фактически элементы), которые находятся внутри #container
. Однако, как мы узнали, jQuery и собственный querySelectorAll
работают справа налево. Это означает, что jQuery будет буквально захватывать каждый элемент в DOM и определять, установлен ли для его disabled
атрибута значение true. Обратите внимание, что нет предварительной фильтрации, чтобы сначала найти все входные данные на странице. Вместо этого каждый элемент в DOM будет запрошен.
1
2
3
4
|
// From the jQuery Source
disabled: function( elem ) {
return elem.disabled === true;
}
|
Как только он скомпилировал коллекцию, он перемещается вверх по цепочке к родителю и определяет, является ли он #container
. Конечно, это не эффективно, и, хотя это правда, что, возможно, слишком большое внимание в сообществе уделяется производительности селекторов, мы все равно должны стремиться не писать чрезмерно интенсивные селекторы, когда это возможно.
Вы можете немного улучшить этот селектор, выполнив:
1
2
|
// Better
$(‘#container > input:disabled’);
|
Этот код сначала ограничит запрос всеми входными данными на странице (а не каждым элементом). Более того, мы можем снова использовать метод find
или children
.
1
|
$(‘#container’).children(‘input:disabled’);
|
Не беспокойся слишком много
Для меня важно повторить, что вам, честно говоря, не нужно слишком беспокоиться о производительности селектора. В jQuery есть множество оптимизаций, которые помогут вам. Как правило, лучше сосредоточиться на более крупных позициях, таких как организация и структура кода.
Например, если Sizzle сталкивается с селектором вроде $('#box p')
, это правда, что он работает справа налево, но есть также быстрая оптимизация регулярного выражения, которая сначала определит, является ли первый раздел селектора id
Если это так, он будет использовать это в качестве контекста при поиске тегов абзаца.
Тем не менее, всегда полезно знать, что происходит за кулисами — по крайней мере, на очень низком уровне.