Какой самый быстрый метод выбора дочерних элементов в jQuery?

101

Насколько мне известно, есть несколько способов выбора дочерних элементов в jQuery .

//Store parent in a variable  
var $parent = $("#parent");

Метод 1 (с использованием прицела)

$(".child", $parent).show();

Метод 2 (метод find ())

$parent.find(".child").show();

Метод 3 (только для непосредственных детей)

$parent.children(".child").show();

Метод 4 (через селектор CSS) - предложен @spinon

$("#parent > .child").show();

Метод 5 (идентичный методу 2 ) - согласно @Kai

$("#parent .child").show();

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

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

Марко
источник
Кроме того, @spinon - это только для непосредственных детей? Спецификация CSS гласит: «Соответствует любому элементу F, который является потомком элемента E.»
Marko
7
Вам действительно не нужно беспокоиться о том, что из этого быстрее (если только вы не выполняете действительно большие манипуляции с dom) ... jQuery был создан, чтобы быть потрясающе быстрым ...
Рейгель
У меня есть HTML-файл размером 2 МБ, не спрашивайте, как и почему :)
Марко
1
Да. Только потомки первого уровня.
spinon
Есть еще один способ. $ ("# родитель. ребенок"). show (); который идентичен способу №2. :)
Кай

Ответы:

95

Метод 1 и метод 2 идентичны с той лишь разницей, что методу 1 необходимо проанализировать переданную область и преобразовать ее в вызов $parent.find(".child").show();.

Метод 4 и метод 5 должны проанализировать селектор, а затем просто вызвать: $('#parent').children().filter('.child')и $('#parent').filter('.child')соответственно.

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

На основе пересмотренных тестов скорости Anurag здесь: http://jsfiddle.net/QLV9y/1/

Тест скорости: (больше значит лучше)

В Chrome лучше всего подходит метод 3, затем метод 1/2, а затем 4/5.

введите описание изображения здесь

В Firefox лучше всего использовать метод 3, затем метод 1/2, а затем 4/5.

введите описание изображения здесь

В Opera лучше всего подходит метод 3, затем метод 4/5, а затем 1/2.

введите описание изображения здесь

В IE 8 , хотя в целом он медленнее, чем в других браузерах, он по-прежнему следует методу 3, 1,2,4,5 порядка.

введите описание изображения здесь

В целом, метод 3 - это лучший метод для использования, поскольку он вызывается напрямую, и ему не нужно проходить более одного уровня дочерних элементов, в отличие от метода 1/2, и его не нужно анализировать, как метод 4/5.

Однако имейте в виду, что в некоторых из них мы сравниваем яблоки с апельсинами, поскольку метод 5 рассматривает всех детей, а не детей первого уровня.

Аарон Харун
источник
Под идентичностью вы имеете в виду, что они оба используют одну и ту же логику для поиска?
Marko
4
Разве вы не имеете в виду, что методы 1 и 2 идентичны?
Guffa
Спасибо, @Aaron, я бы хотел узнать, что думают другие, я приму твой ответ, если все согласятся. Ура :)
Марко
@JP, я имею в виду, что требуется дополнительное время, чтобы распознать, что область видимости передается для преобразования ее в $parent.find(".child");команду.
Аарон Харун
2
@Aaron @Marko - тесты могут быть немного искажены, поскольку мы всегда используем корневой узел в качестве контекста, а документ довольно большой. Несмотря на это, я вижу, что 1 и 2 выстраиваются в линию в пределах 20 операций / сек на большинстве прогонов. По сравнению с 1 и 2, 4 примерно на 100-200 операций медленнее, а 5 примерно на 400 операций медленнее, что понятно, потому что он проходит через всех потомков, а не только детей. График - tinyurl.com/25p4dhq
Anurag
13

Способ 1

Не может быть короче и быстрее с помощью jQuery. Этот вызов непосредственно получает вниз $(context).find(selector)( метод 2 , из - за optimazation) , который в свою очередь, звонки getElementById.

Способ 2

Делает то же самое, но без ненужных внутренних вызовов функций.

Способ 3

использование children()выполняется быстрее, чем использование find(), но, конечно, children()будет найдено только прямые дочерние элементы корневого элемента, тогда как find()будет выполняться рекурсивный поиск сверху вниз для всех дочерних элементов (включая дочерние элементы)

Метод 4

Использование подобных селекторов должно быть медленнее. Поскольку sizzle(который является механизмом выбора из jQuery) работает справа налево , он .childсначала будет соответствовать ВСЕМ классам, прежде чем он посмотрит, являются ли они прямым потомком от id 'parent'.

Метод 5

Как вы правильно заявили, этот вызов также создаст $(context).find(selector)вызов из-за некоторой оптимизации внутри jQueryфункции, иначе он также может пройти (медленнее) sizzle engine.

Дженди
источник
2
Вы ведь не говорите о var $ parent = $ ("# parent")? Я не понимаю, как в методе 1 можно использовать getElementById, если у элемента есть класс?
Марко
1
Я хотел согласиться, но в методе 1 документация говорит: « Internally, selector context is implemented with the .find() methodПожалуйста, обновите, я знаю, что вы запутались на этикетках OP :)»
Рейгель 05
@Reigel: правда исправил это. @Marko: синтаксический анализ #parentпредставляет собой идентификатор, если это класс, он, getElementByIdочевидно , не будет использоваться .
jAndy 05
10

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

При использовании jQuery 2.1 в браузерах, совместимых с HTML5 и CSS3, производительность меняется.

Вот сценарий и результаты теста:

function doTest(selectorCallback) {
    var iterations = 100000;

    // Record the starting time, in UTC milliseconds.
    var start = new Date().getTime();

    for (var i = 0; i < iterations; i++) {
        // Execute the selector. The result does not need to be used or assigned
        selectorCallback();
    }

    // Determine how many milliseconds elapsed and return
    return new Date().getTime() - start;
}

function start() {
    jQuery('#stats').html('Testing...');
    var results = '';

    results += "$('#parent .child'): " + doTest(function() { jQuery('#parent .child'); }) + "ms";
    results += "<br/>$('#parent > .child'): " + doTest(function() { jQuery('#parent > .child'); }) + "ms";
    results += "<br/>$('#parent').children('.child'): " + doTest(function() { jQuery('#parent').children('.child'); }) + "ms";
    results += "<br/>$('#parent').find('.child'): " + doTest(function() { jQuery('#parent').find('.child'); }) + "ms";
    $parent = jQuery('#parent');
    results += "<br/>$parent.find('.child'): " + doTest(function() { $parent.find('.child'); }) + "ms";

    jQuery('#stats').html(results);
}
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=7, IE=8, IE=9, chrome=1" />
    <title>HTML5 test</title>
    <script src="//code.jquery.com/jquery-2.1.1.js"></script>
</head>
<body>

<div id="stats"></div>
<button onclick="start()">Test</button>

<div>
    <div id="parent">
        <div class="child"></div>
        <div class="child"></div>
        <div class="child"></div>
        <div class="child"></div>
        <div class="child"></div>
        <div class="child"></div>
        <div class="child"></div>
    </div>
</div>

</body>
</html>

Итак, за 100 000 итераций я получаю:

Статистика селектора JS jQuery

(Я добавил их как img для форматирования.)

Вы можете запустить фрагмент кода самостоятельно для проверки;)

Васил Попов
источник
Ой! Тогда похоже .find()отлично справляется. Продолжаю его использовать. :)
Эндрю Сурду