Jaka jest najszybsza metoda wybierania elementów podrzędnych w jQuery?

101

O ile wiem, w jQuery można wybierać elementy potomne na wiele sposobów .

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

Metoda 1 (przy użyciu zakresu)

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

Metoda 2 ( metoda find ())

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

Metoda 3 (tylko dla bezpośrednich dzieci)

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

Metoda 4 (przez selektor CSS) - sugerowana przez @spinon

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

Metoda 5 (identyczna z metodą 2 ) - zgodnie z @Kai

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

Nie jestem zaznajomiony z profilowaniem, aby móc to zbadać samodzielnie, więc chciałbym zobaczyć, co masz do powiedzenia.

PS Rozumiem, że to możliwe powtórzenie tego pytania, ale nie obejmuje wszystkich metod.

Marko
źródło
Ponadto @spinon - czy to tylko dla najbliższych dzieci? Specyfikacja CSS mówi: „Pasuje do dowolnego elementu F, który jest dzieckiem elementu E.”
Marko,
7
Tak naprawdę nie musisz się martwić, która z nich jest szybsza (chyba że robisz naprawdę dużą manipulację
domem
Mam plik HTML 2MB, nie pytaj jak ani dlaczego :)
Marko,
1
Tak. Tylko potomkowie pierwszego poziomu.
spinon
Jest jeszcze jeden sposób. $ ("# rodzic .child"). show (); który jest identyczny jak sposób # 2. :)
Kai,

Odpowiedzi:

95

Metoda 1 i metoda 2 są identyczne, z tą różnicą, że metoda 1 musi przeanalizować przekazany zakres i przetłumaczyć go na wywołanie $parent.find(".child").show();.

Metody 4 i 5 muszą przeanalizować selektor, a następnie po prostu wywołać odpowiednio : $('#parent').children().filter('.child')i $('#parent').filter('.child').

Zatem metoda 3 zawsze będzie najszybsza, ponieważ wymaga wykonania najmniejszej ilości pracy i wykorzystuje najbardziej bezpośrednią metodę, aby zdobyć dzieci pierwszego stopnia.

Na podstawie poprawionych testów prędkości Anurag tutaj: http://jsfiddle.net/QLV9y/1/

Test prędkości: (im więcej, tym lepiej)

W przeglądarce Chrome metoda 3 jest najlepsza, a następnie metoda 1/2, a następnie 4/5

wprowadź opis obrazu tutaj

W przeglądarce Firefox metoda 3 jest nadal najlepsza, a następnie metoda 1/2, a następnie 4/5

wprowadź opis obrazu tutaj

W przeglądarce Opera metoda 3 jest nadal najlepsza, a następnie metoda 4/5, a następnie 1/2

wprowadź opis obrazu tutaj

W IE 8 , chociaż ogólnie wolniejszy niż w innych przeglądarkach, nadal jest zgodny z kolejnością metody 3, 1,2,4,5.

wprowadź opis obrazu tutaj

Ogólnie rzecz biorąc, metoda 3 jest ogólnie najlepszą metodą do użycia, ponieważ jest wywoływana bezpośrednio i nie musi przechodzić przez więcej niż jeden poziom elementów podrzędnych w przeciwieństwie do metody 1/2 i nie musi być analizowana jak metoda 4/5

Należy jednak pamiętać, że w niektórych z nich porównujemy jabłka do pomarańczy, ponieważ Metoda 5 dotyczy wszystkich dzieci, a nie dzieci pierwszego poziomu.

Aaron Harun
źródło
Przez identyczne masz na myśli, że oboje używają tej samej logiki do wyszukiwania?
Marko,
4
Czy nie masz na myśli, że metody 1 i 2 są identyczne?
Guffa,
Dzięki @Aaron - chciałbym zobaczyć, co myślą inni. Przyjmę twoją odpowiedź, jeśli wszyscy się zgodzą. Pozdrawiam :)
Marko
@JP, mam na myśli, że potrzeba dodatkowego czasu, aby rozpoznać, że przekazywany jest zakres, aby przetłumaczyć go na $parent.find(".child");polecenie.
Aaron Harun,
2
@Aaron @Marko - Testy mogą być trochę wypaczone, ponieważ zawsze używamy węzła głównego jako kontekstu, a dokument jest dość duży. Mimo to widzę, jak 1 i 2 ustawiają się w linii w ciągu 20 operacji na sekundę w większości biegów. W porównaniu do 1 i 2, 4 jest o około 100-200 operacji wolniejsze, a 5 jest o około 400 operacji wolniejsze, co jest zrozumiałe, ponieważ przechodzi przez wszystkich potomków, a nie tylko dzieci. Wykres - tinyurl.com/25p4dhq
Anurag,
13

Metoda 1

Nie można być krótszym i szybszym przy użyciu jQuery. To wywołanie sprowadza się bezpośrednio do $(context).find(selector)( metoda 2 , ze względu na optymalizację), która z kolei wywołujegetElementById .

Metoda 2

Robi to samo, ale bez niepotrzebnych wywołań funkcji wewnętrznych.

Metoda 3

używanie children()jest szybsze niż używanie find(), ale oczywiście children()znajdzie tylko bezpośrednie elementy potomne elementu głównego, podczas gdy find()będzie wyszukiwać rekursywnie z góry na dół do wszystkich elementów potomnych (w tym elementów podrzędnych)

Metoda 4

Korzystanie z takich selektorów musi być wolniejsze. Ponieważ sizzle(który jest silnikiem selektora z jQuery) działa od prawej do lewej , najpierw dopasuje WSZYSTKIE klasy, .childzanim sprawdzi, czy są one bezpośrednim dzieckiem z id 'rodzic'.

Metoda 5

Jak poprawnie stwierdziłeś, wywołanie to również utworzy $(context).find(selector)wywołanie, z powodu pewnej optymalizacji w jQueryfunkcji, w przeciwnym razie może również przejść przez (wolniej) sizzle engine.

jAndy
źródło
2
Nie mówisz o var $ parent = $ ("# rodzic"), prawda? Nie widzę, jak metoda 1 mogłaby użyć metody getElementById, gdy element ma klasę?
Marko,
1
Chciałem się zgodzić, ale w metodzie 1 dokumentacja mówi: Internally, selector context is implemented with the .find() method-proszę o aktualizację, wiem, że
pomyliłeś
@Reigel: true naprawiono to. @Marko: parsowanie #parentreprezentuje id, jeśli jest to klasa, to getElementByIdoczywiście nie będzie używane .
jAndy
10

Ponieważ jest to stary post, a wraz z upływem czasu wszystko się zmienia. Zrobiłem kilka testów na ostatnich wersjach przeglądarek do tej pory i zamieszczam je tutaj, aby uniknąć nieporozumień.

Korzystanie z jQuery 2.1 w przeglądarkach zgodnych z HTML5 i CSS3 zmienia wydajność.

Oto scenariusz testu i wyniki:

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>

Tak więc za 100 000 iteracji otrzymuję:

Statystyki selektora JS jQuery

(Dodałem je jako img do celów formatowania).

Możesz samodzielnie uruchomić fragment kodu, aby przetestować;)

Vasil Popov
źródło
O! Wygląda na to, że .find()wykonuje świetną robotę. Nadal z niego korzystać. :)
Andrew Surdu,