Статьи

Совет: думайте справа налево с помощью jQuery

Как говорящие на английском языке, наши умы направлены на интерпретацию данных и текста слева направо. Однако, как выясняется, многие из современных механизмов выбора JavaScript ( jQuery , YUI 3 , NWMatcher ) и собственный querySelectorAll анализируют строки выбора справа налево.

Важно отметить, что чаще всего вам не нужно слишком беспокоиться о производительности селектора — если ваши селекторы не противны. Sizzle jQuery невероятно быстр и любезен.


Рассмотрим следующий селектор:

1
$(‘.box p’);

Хотя некоторые — обычно более старые — механизмы выбора сначала будут запрашивать DOM для элемента с class box , а затем переходят к поиску любых p тегов, которые являются дочерними, jQuery работает в обратном порядке. Он начинается с запроса DOM ко всем тегам абзаца на странице, а затем .box родительские узлы и ищет .box .

Мы можем использовать отличный сайт 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’);
JS Perf

Изображение выше показывает, что использование 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 Если это так, он будет использовать это в качестве контекста при поиске тегов абзаца.

Тем не менее, всегда полезно знать, что происходит за кулисами — по крайней мере, на очень низком уровне.