Как оптимизировать $.find(). First()?

Мне нужно получить первый элемент.

Я делаю это с этим кодом...

$(element).find('.x').first();

Насколько я понимаю, этот код...

  1. Получает все элементы из element что совпало .x,
  2. Удаляет ненужные элементы;

Есть ли лучший способ сделать это? подобно $.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>

так что на самом деле это не то, что вы ищете (если вы имеете в виду общее решение). Другие мнения: во-первых, и это, кажется, правильный подход

Это должно быть лучше

$(element).find('.x:first');

Ваше узкое место действительно .find(), который ищет всех потомков, а не только непосредственных детей.

Кроме того, вы ищете класс .x (который использует пользовательский поиск jQuery) вместо идентификатора или тэга (которые используют собственные методы DOM).

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

Лучше написать:

$('a:first');

То, что вы пишете, находится в "элементе", найдите ".x" и верните первый ". И это можно выразить так

$('.x:first', element);

Использование :first селектор:

$(element).find('.x:first')
Другие вопросы по тегам