Лучший способ оптимизировать селектор jQuery и почему?

Я использую этот селектор jQuery несколько раз в моем JSP:

 $("#customers tbody tr td input[type='checkbox'][name='selectedCustomers']")

Решение, которое я нашел в некоторых блогах, это то, что я должен сделать в первую очередь:

var customer=$('#customers')

И затем используйте вышеуказанный объект клиента для дальнейших вызовов.

 customer.find("tbody tr td input[type='checkbox'][name='selectedCustomers']")

Мой вопрос в том, поможет ли это решение и почему?

Мое понимание

Когда я делаю

$("#customers tbody tr td input[type='checkbox'][name='selectedCustomers']")

jQuery внутренне сначала получит объект, связанный с div id="customers" (by document.getElementById( "клиенты" )), а затем перейдет к указанному checkbox. И если я пойду по предлагаемому решению, то document.getElementById("customers") будет запущен только один раз, а остальные будут одинаковыми. Поэтому я спасаю себя от ненужного множественного document.getElementById, но остальное будет таким же. Правильно ли я понимаю? Если да, то, насколько мне известно, document.getElementById более дорогостоящая операция?

EDIT: -

Я не использую только выше указанного селектора несколько раз, но также и другой возможный селектор под div id = "клиент". Поэтому вопрос снова заключается в том, что разница в производительности, если я сначала кэширую объект клиента, и если я этого не делаю?

Ответы

Ответ 1

Вам не нужно быть таким специфическим. Я предполагаю, самое большее, это:

$('#customers td [name="selectedCustomers"]')

..., что должно повысить производительность. Затем, если вы каждый раз запрашиваете selectedCustomers, вы должны кэшировать все это:

var selectedCustomers = $('#customers td [name="selectedCustomers"]');

В противном случае, если имя динамическое, и у вас есть только один элемент с тем же именем на странице...

var item = $(document.getElementsByName(someName)[0]);

Кэширование только $('#customers'), с другой стороны, довольно бессмысленно. .find on customers будет работать так же, как и весь селектор, в первую очередь, с поддержкой querySelector.

Ответ 2

Кажется, вам не хватает основной точки кеширования объекта. После того, как объект будет кэширован, любой дальнейший обход или манипуляция внутри этого селектора будет выполняться на сохраненном объекте и не требует поиска DOM, чтобы сначала найти селектор и создать коллекцию каждый раз, когда вам нужно его использовать.

Каждый раз, когда вы вызываете $("#customers tbody tr td input[type='checkbox'][name='selectedCustomers']"), поиск документа должен выполняться для создания коллекции элементов, прежде чем любые изменения могут быть внесены в коллекцию.

Кэширование средства сбора данных не требует дальнейших поисков, поэтому улучшается производительность

/* locate and store the collection once*/
var $checkboxes=$("#customers tbody input[name='selectedCustomers']");
/* look within previously stored collection*/
$checkboxes.filter(/* expression*/ ).doSomething();

Использование document.getElementById будет быстрее, чем поиск в jQuery, просто потому, что он не требует дополнительных вызовов функций, созданных библиотекой jQuery. Однако, если вы хотите использовать результат как объект jQuery, например: $( document.getElementById('foo'))  выигрыши, вероятно, не стоит беспокоиться об одном использовании для кэширования объекта

Ответ 3

Итак, я избавляюсь от ненужного множественного document.getElementById, но остальное будет таким же.

Да. Но, возможно, также нет, поскольку селектора оцениваются справа налево (см. эта статья или this SO вопрос). И если предположить, что это эффективный движок, ему было меньше работы, если он делает эту оценку только в части дерева документов, если вы сначала выберите #customers, а затем .find(). Но я не уверен в этом на 100%.

Является ли document.getElementById более дорогостоящей операцией?

Нет, это очень дешево. Идентификаторы являются стандартным атрибутом для идентификации отдельных элементов, и браузеры будут создавать для него очень эффективные таблицы поиска - вы можете считать, что это почти O(1).

customer.find("tbody tr td input[type='checkbox'][name='selectedCustomers']")

С другой стороны, запросы выбора DOM, которые должны оценивать дерево DOM, очень дорогостоящи, особенно если они выполняются вручную в JS-коде (jQuery sizzle) и не являются родными - хотя этот довольно простой запрос будет делегирован на native querySelectorAll.

Я предполагаю, что #customers - ваш элемент таблицы. Поэтому для производительности пропустите теги tbody tr td, они обязательны (если вы не использовали их для явного исключения флажков из элементов <thead>/<tfoot> или <th>). В любом случае вы не найдете <input> в качестве прямого дочернего элемента таблицы, а механизм выбора гораздо меньше.

Кроме того, если вы хорошо знаете свою разметку и можете сделать предположение, что только флажки имеют этот атрибут name, вы можете также опустить селектор атрибутов типов тэгов и типов. И это означает, что вы можете делегировать нативный getElementsByName, который должен немного повысить производительность:

$(document.getElementById("customers").getElementsByName("selectedCustomers"))

Если вам нужно проверить, что элементы являются флажками, вы все равно можете их фильтровать. При этом вы можете получить

$(customer.get(0).getElementsByName("selectedCustomers")).filter(":checkbox")

Однако для доказательства повышения производительности вы можете тестировать, тестировать, тестировать; и вам нужно будет сделать это на своей полной странице.

Ответ 4

http://jsperf.com/different-jquery-selector-tests

Проверьте этот маленький тест. В основном $('# div'). Find ('# p'); - самый быстрый и $('div'). Find ('# p'); является самым медленным.