Какой самый быстрый способ получить элемент DOM? - PullRequest
6 голосов
/ 03 апреля 2009

Я настраиваю производительность своего кода и с удивлением обнаруживаю, что узким местом является не вставка dom-узла, а выбор.

Это быстро:

var row = jquery(rowHTML).appendTo(oThis.parentTable);

но последующее получение элемента внутри "строки" происходит медленно:

var checkbox = jquery(".checkbox input", row);

Мне нужно установить флажок в каждой строке, чтобы я мог прикрепить к нему обработчик событий. Установка флажка - ПОЧТИ 10X КАК МЕДЛЕННО, поскольку вставляется вся родительская строка.

Что я здесь не так делаю?

Ответы [ 7 ]

13 голосов
/ 04 апреля 2009

DOM манипулирование использует собственные функции для выполнения простых операций. Поставщики браузеров оптимизируют их. Вы строите строку из HTML. Внутренне jQuery использует .innerHTML для создания коллекции, которая затем исправляет мега-быстрый синтаксический анализатор браузера.

Выбор медленный по сравнению, потому что JS-коду необходимо многократно проходить через DOM. Более новые браузеры имеют встроенную обработку выбора, которая обеспечивает резкое ускорение JS на основе селектора. Со временем это станет меньшей проблемой.

Вот как разбивается запрос $(".checkbox input", row):

  1. row.getElementsByTagName('*');
  2. for проходит через каждый возвращенный элемент (все элементы в строке) и тестирует elements[i].className с /(\s|^)checkbox(\s|$)/.
  3. цикл для каждого оставшегося элемента и сбор matched[i].getElementsByTagName('input');
  4. уникальная финальная коллекция.

Это отличается для jQuery 1.3, поскольку его движок движется по селектору наоборот, начиная с получения всех входных элементов и затем проверяя родительские элементы.

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

Если вы знаете, к какому типу элемента относится .checkbox:

$("td.checkbox input", row);

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

Тест одного класса является самым медленным из распространенных селекторов, которые люди фактически используют .

Упрощенный выбор:

$("input[type=checkbox]", row);

Один цикл быстрее, чем два цикла. Это только находит входные элементы и затем непосредственно фильтрует их по атрибуту типа. Поскольку sub / child-elements никогда не используются, unique также может быть пропущен (и умные движки попытаются сделать это, так как unique медленный).

Более прямой селектор:

$("td:first.checkbox input", row);

Более сложный селектор на самом деле может быть быстрее, если он более прямой (YMMV).

Если возможно, переместите контекст поиска на уровень таблицы:

Под этим я подразумеваю, что вместо циклического обхода строк и поиска флажка в каждом из них оставьте их в покое до окончания цикла, а затем выберите их все одновременно:

$("tr td:first.checkbox input", table);

Смысл этого состоит в том, чтобы устранить накладные расходы при повторном запуске двигателя селектора, но вместо этого делать все за один раз. Это представлено здесь для полноты, а не для того, что, я думаю, могло бы привести к огромным ускорениям.

Не выбирайте:

Создайте ряд из битов, назначая события по мере продвижения.

var row = $( '<tr></tr>' );
var cell = $( '<td class="checkbox"></td>' ).appendTo( row );
$( '<input type="checkbox" name="..."/>' ).appendTo( cell ).click(/* ... */);

Это может быть невозможно по причинам, не зависящим от Ajax или других шаблонов. Кроме того, скорость может не стоить превращать ваш код в такого рода беспорядок, но иногда это может иметь смысл.

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

$('table').change(function(e){
  // you may want a faster check...
  if ( $(e.target).is('input[type=checkbox]') ) {
    // do some stuff ...
  }
});

Таким образом, вы ничего не делаете, пока пользователь не запросит это. Самый быстрый. : -)

2 голосов
/ 03 апреля 2009

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

jQuery поддерживает это с помощью функции live().

2 голосов
/ 03 апреля 2009
var checkbox = jquery(".checkbox input", row);

Это обход всего дерева dom, чтобы найти флажок. Возможно, вы могли бы ускорить его, изменив селектор на идентификатор, который может использовать встроенную в браузер функциональность getElementById.

var checkbox = jquery("#checkbox input", row);

Вы также можете использовать свою строку в качестве отправной точки для поиска в DOM, как показано в следующем примере. Теперь вы не анализируете все дерево DOM снова, чтобы найти соответствующий элемент.

var row = jquery(rowHTML).appendTo(oThis.parentTable);
row.children(".checkbox input");
1 голос
/ 03 апреля 2009

Попробуйте использовать Хитрый , он делает упор на производительность.

1 голос
/ 03 апреля 2009

Попробуйте поместить имя класса в само поле ввода. Это может оказаться быстрее.

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

Просто просматривая все элементы с классом, имеющимся в поле ввода, вы можете увидеть некоторое ускорение.

0 голосов
/ 02 февраля 2016

Самый быстрый способ получить элемент DOM - это использовать чистый JavaScript и вызывать его по ID.

var element = document.getElementById('element);
0 голосов
/ 03 апреля 2009

Если вы ищете производительность, селекторы jQuery работают очень медленно. В приведенном примере он должен отсканировать полное дерево DOM и проверить классы CSS и т. Д., Чтобы найти соответствующие узлы.

Значительно быстрее использовать собственные методы DOM. Здесь есть несколько интересных сравнений производительности библиотеки:

http://ajaxian.com/archives/taskspeed-more-benchmarks-for-the-libraries-and-browsers

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...