Является ли обход jQuery предпочтительным для селекторов?

Используется ли $("#vacations").find("li").last() лучше, чем $("#vacations li:last")?

История и мои мысли:

Я играл с приятным интерактивным попробовать jQuery tutorial, и в одной из задач говорится:

Когда вы просматриваете свой код, вы замечаете, что кто-то другой выбирает последний отпуск с: $( "# vacations li: last" ). Вы смотрите на это, и вы думаете: "Траверс будет делать это быстрее!" Вы должны действовать по этим мыслям, реорганизовать этот код, чтобы найти последний li в #vacations, используя обход вместо.

Почему я так думаю? Для меня использование селекторов выглядит немного выше, чем пересечение. На мой взгляд, когда я указываю селектор, это зависит от jQuery, как лучше получить единственный результат, который мне нужен (без необходимости возврата промежуточных результатов).

Что это за дополнительные накладные расходы на использование композитных селекторов? Это потому, что текущая реализация логики селекторов просто анализирует строку и использует API обхода? Разбирает строку, которая замедляется? Есть ли вероятность того, что будущая реализация будет использовать тот факт, что ему не нужно возвращать промежуточные результаты и будет быстрее, чем обход?

Ответ 1

Нет ответа на этот вопрос, но в отношении селектора :last, который вы используете, это проприетарное расширение стандарта Selectors API. Из-за этого это недопустимо для использования с нативным методом .querySelectorAll.

Что Sizzle в основном пытается использовать ваш селектор с .querySelectorAll, и если он выбрасывает исключение из-за неверного селектора, он по умолчанию будет использовать выбор/фильтрацию DOM на основе JavaScript.

Это означает, что включение селекторов типа :last приведет к тому, что вы не получите ускорение DOM с помощью собственного кода.

Кроме того, включены оптимизации, так что, когда ваш селектор очень прост, например, только идентификатор или имя элемента, будут использоваться нативные getElementById и getElementsByTagName, которые очень быстр; обычно даже быстрее, чем querySelectorAll.

И поскольку метод .last() просто захватывает последний элемент в коллекции, а не фильтрует все элементы, что обычно делают фильтры Sizzle (по крайней мере, они использовались), что также даст толчок.

ИМО, держитесь подальше от проприетарного материала. Теперь, когда .querySelectorAll довольно вездесущ, существуют реальные преимущества только при использовании селекторов, соответствующих стандарту. Сделайте еще один выбор DOM фильтрационного сообщения.


В случае $("#vacations").find("li") не беспокойтесь о промежуточных результатах. Это будет использовать getElementById, за которым следует getElementsByTagName, и будет очень быстрым.

Если вы действительно очень обеспокоены скоростью, уменьшите использование jQuery и напрямую используйте DOM.


В настоящее время вы найдете заметки в документах для селекторов типа :last, которые предупреждают вас о потере производительности:

Поскольку: последний является расширением jQuery, а не частью спецификации CSS, запросы с использованием :last не могут воспользоваться повышением производительности, предоставляемым встроенным методом DOM querySelectorAll(). Для достижения наилучшей производительности при использовании :last для выбора элементов сначала выберите элементы, используя чистый селектор CSS, затем используйте .filter(":last").

Но я бы не согласился, что .filter(":last") будет хорошей заменой. Гораздо лучше были бы методы типа .last(), которые будут нацелены на элемент непосредственно, а не на фильтрацию набора. У меня такое чувство, что они просто хотят, чтобы люди продолжали использовать своих нестандартных селекторов. ИМО, вам лучше просто забыть о них.

Ответ 2

Вот тест для вашей установки: http://jsperf.com/andrey-s-jquery-traversal

Sizzle, механизм выбора jQuery, анализирует строку с помощью регулярного выражения и пытается ускорить использование очень простых селекторов с помощью getElementById и getElementsByTagName. Если ваш селектор является чем-то более сложным, чем #foo и img, он попытается использовать querySelectorAll, который принимает только допустимые селекторы CSS (нет :radio, :eq, :checkbox или других специфичных для jQuery псевдо-селекторы).

Строка селектора является менее читаемой и медленной, поэтому нет причин для ее использования.

Разбирая селекторную цепочку на простые куски, которые Sizzle может быстро разбора (#id и tagname), вы в основном просто соединяете вызовы getElementById и getElementsByTagName, что примерно так же быстро, как вы можете получить.