Как оптимизировать $.find(). First()?
Мне нужно получить первый элемент.
Я делаю это с этим кодом...
$(element).find('.x').first();
Насколько я понимаю, этот код...
- Получает все элементы из
element
что совпало.x
, - Удаляет ненужные элементы;
Есть ли лучший способ сделать это? подобно $.findOne()
или что-то?
10 ответов
Согласно документации JQuery:
Поскольку:first является расширением jQuery и не является частью спецификации CSS, запросы, использующие:first, не могут воспользоваться преимуществами повышения производительности, обеспечиваемыми собственным методом DOM querySelectorAll(). Для достижения максимальной производительности при использовании: сначала выберите элементы, сначала выберите элементы с помощью чистого селектора CSS, а затем используйте.filter(":first").
Так что переписать ваш селектор на:
$(element).find('.x').filter(":first")
или (этот даст вам только прямых потомков и будет быстрее, чем .find
, если вы не ищете вложенные элементы тоже)
$(element).children('.x').filter(":first")
должен дать вам лучшие результаты.
Обновление После ценных вкладов от James Montagne и user113716 (см. Комментарии) кажется, что эти два быстрее, чем .filter(':first')
вопреки тому, что утверждает док.
$(element).find('.x').first(); // faster
$($(element).find('.x')[0]); // fastest
Если вы хотите, чтобы это было очень быстро, вы должны использовать собственные методы браузера. Поддержка современных браузеров querySelector
[документы]:
var $result;
if(element.querySelector) {
$result = $(element.querySelector('.x'));
}
else {
$result = $(element).find('.x').first();
}
Использование немного ограничено, так как это будет работать только в том случае, если element
является единственным элементом, и если селектор является допустимым селектором CSS. Вы могли бы сделать плагин из этого. Но тогда, если вы рассмотрите все случаи, такие как множественные элементы и т. Д., Вероятно, больше нет никаких преимуществ.
Итак, еще раз, если у вас есть очень конкретный вариант использования, это может быть полезно, если нет, придерживайтесь jQuery.
Обновление: Оказывается, создание плагина все еще быстрее: бенчмарк jsPerf
(function($) {
$.fn.findOne = function(selector) {
try {
var element, i = 0, l = this.length;
while(i < l && (element = this[i].querySelector(selector)) === null) {
i++;
}
return $(element);
}
catch(e) {
return this.find(selector).first();
}
};
}(jQuery));
Как это работает:
Плагин перебирает выбранные элементы DOM и вызывает querySelector
на каждом из них. Как только элемент найден, цикл завершается и возвращает найденный элемент. Есть две причины, по которым может возникнуть исключение:
- Браузеры не поддерживают
querySelector
- Селектор не является чистым селектором CSS
В обоих случаях плагин будет использовать обычный метод jQuery.
Как бы безумно это ни казалось, в каждом тесте производительности, который я видел, .first()
имеет лучшую производительность, чем :first
,
Как полагают большинство людей, кажется, что $(element).find(".x:first")
должен иметь лучшую производительность. Однако на самом деле .first
быстрее. Я не заглядывал во внутренности jquery, чтобы понять почему.
http://jsperf.com/jquery-select-first
И видимо используя [0]
и затем перемотка в объект jquery является самой быстрой:
$($(element).find(".x")[0])
РЕДАКТИРОВАТЬ: см. Ответ mrchief для объяснения почему. Видимо, теперь они добавили его в документацию.
Вы могли бы объединить $(element)
а также .find()
звонки с использованием селектора потомков; Я не уверен в сравнении производительности:
$("#element .x").first().hide();
Этот способ хорош в соответствии с документацией jQuery или, по крайней мере, лучше, чем при использовании :first
селектор.
Вы можете попробовать в качестве альтернативы .filter(":first")
или получить первый элемент, используя метод доступа к массиву .find()
результат [0]
,
Кроме того, вместо .find()
Вы можете изменить это на:
$('.x', element)
Чтобы сузить поиск до .x
элементы внутри элемента, поиск по всему документу.
Как насчет использования первого класса псевдо-класса? лайк
$(element).find('.x:first-child')
Однако это может вызвать проблемы, если ваша структура
<div>
<p></p>
</div>
<div>
<p></p>
</div>
так что на самом деле это не то, что вы ищете (если вы имеете в виду общее решение). Другие мнения: во-первых, и это, кажется, правильный подход
Ваше узкое место действительно .find()
, который ищет всех потомков, а не только непосредственных детей.
Кроме того, вы ищете класс .x
(который использует пользовательский поиск jQuery) вместо идентификатора или тэга (которые используют собственные методы DOM).
Я бы воспользовался ответом Мркифа, а затем, по возможности, исправил бы эти два узких места, чтобы ускорить ваш выбор.
Лучше написать:
$('a:first');
То, что вы пишете, находится в "элементе", найдите ".x" и верните первый ". И это можно выразить так
$('.x:first', element);