Как оптимизировать $ .find (). First ()? - PullRequest
5 голосов
/ 24 августа 2011

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

Я делаю это с помощью этого кода ...

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

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

  1. Извлекает все элементы из element, которые соответствуют .x,
  2. Удаляет ненужные элементы;

Есть ли лучший способ сделать это? Как $.findOne() или что-то?

Ответы [ 10 ]

11 голосов
/ 24 августа 2011

Согласно документации jQuery:

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

Переписав свой селектор на:

$(element).find('.x').filter(":first")

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

$(element).children('.x').filter(":first")

должен дать вам лучшерезультаты.


Обновление После ценных вкладов kingjiv и patrick dw (см. комментарии), кажется, что эти двабыстрее, чем .filter(':first') вопреки тому, что утверждает документ.

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

$($(element).find('.x')[0]);     // fastest
4 голосов
/ 24 августа 2011

Если вы хотите, чтобы это было очень быстро, вы должны использовать нативные методы браузера. Современные браузеры поддерживают querySelector [документы] :

var $result;
if(element.querySelector) {
    $result = $(element.querySelector('.x'));
}
else {
    $result = $(element).find('.x').first();
}

Использование немного ограничено, так как оно будет работать, только если element является единственным элементом и если селектор является допустимым селектором CSS. Вы могли бы сделать плагин из этого. Но тогда, если вы рассмотрите все случаи, например, несколько элементов и т. Д., Вы, вероятно, больше не будете иметь никаких преимуществ.

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

Обновление: Получается, что плагин все еще работает быстрее: jsPerf benchmark

(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.

2 голосов
/ 24 августа 2011

Как ни странно, в каждом тесте производительности, который я видел, .first() имеет лучшую производительность, чем :first.

Как предполагает большинство людей, кажется, что использование $(element).find(".x:first") должно иметь лучшую производительность.Однако на самом деле .first быстрее.Я не изучал внутреннюю часть jquery, чтобы выяснить, почему.

http://jsperf.com/jquery-select-first

И, по-видимому, использование [0] и последующая переупаковка в объекте jquery является самым быстрым:

$($(element).find(".x")[0])

РЕДАКТИРОВАТЬ: см. Ответ mrchief для объяснения почему.Видимо, теперь они добавили его в документацию.

0 голосов
/ 24 августа 2011

Вы можете объединить вызовы $(element) и .find(), используя селектор потомков;Я не уверен в сравнении производительности:

$("#element .x").first().hide();
0 голосов
/ 24 августа 2011

Этот способ хорош в соответствии с документацией jQuery или, по крайней мере, лучше, чем использование селектора :first.

Вы можете попробовать в качестве альтернативы .filter(":first") или получить первый элемент, используя метод доступа к массиву, против результата .find() [0].

Кроме того, вместо .find() вы можете изменить его на:

$('.x', element)

Чтобы сузить поиск до .x элементов внутри элемента, необходимо искать весь документ.

0 голосов
/ 24 августа 2011

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

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

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

0 голосов
/ 24 августа 2011

как насчет использования first-child псевдокласса?как

$(element).find('.x:first-child')

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

<div>
   <p></p>
</div>
<div>
   <p></p>
</div>

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

0 голосов
/ 24 августа 2011

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

$('a:first');

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

$('.x:first', element);
0 голосов
/ 24 августа 2011

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

$(element).find('.x:first')
0 голосов
/ 24 августа 2011

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

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