Was ist die schnellste Methode zum Auswählen von untergeordneten Elementen in jQuery?

101

Soweit ich weiß, gibt es in jQuery verschiedene Möglichkeiten, untergeordnete Elemente auszuwählen .

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

Methode 1 (unter Verwendung eines Bereichs)

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

Methode 2 (die find () -Methode)

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

Methode 3 (Nur für unmittelbare Kinder)

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

Methode 4 (über CSS-Selektor) - vorgeschlagen von @spinon

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

Methode 5 (identisch mit Methode 2 ) - gemäß @Kai

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

Ich bin nicht mit Profiling vertraut, um dies selbst untersuchen zu können, daher würde ich gerne sehen, was Sie zu sagen haben.

PS Ich verstehe, dass dies ein mögliches Duplikat dieser Frage ist, aber es werden nicht alle Methoden behandelt.

Marko
quelle
Auch @spinon - ist das nur für unmittelbare Kinder? Die CSS-Spezifikation lautet "Entspricht jedem F-Element, das einem Element E untergeordnet ist."
Marko
7
Sie müssen sich nicht wirklich Sorgen machen, welche davon schneller ist (es sei denn, Sie führen eine wirklich große Dom-Manipulation durch) ... jQuery wurde entwickelt, um schnell fantastisch zu sein ...
Reigel
Ich habe eine 2 MB HTML-Datei, frage nicht wie oder warum :)
Marko
1
Ja. Nur Nachkommen der ersten Ebene.
Spinon
Es gibt noch einen Weg. $ ("# parent .child"). show (); Das ist identisch mit dem Weg # 2. :)
Kai

Antworten:

95

Methode 1 und Methode 2 sind identisch, mit dem einzigen Unterschied, dass Methode 1 den übergebenen Bereich analysieren und in einen Aufruf an übersetzen muss $parent.find(".child").show();.

Methode 4 und Methode 5 sowohl Notwendigkeit , den Selektor parsen und dann einfach anrufen: $('#parent').children().filter('.child')und $('#parent').filter('.child')jeweils.

So Methode 3 wird immer die schnellste sein , weil es die geringste Menge an Arbeit tun muss , und verwendet die direkteste Methode der ersten Ebene Kinder zu bekommen.

Basierend auf Anurags überarbeiteten Geschwindigkeitstests hier: http://jsfiddle.net/QLV9y/1/

Geschwindigkeitstest: (Mehr ist besser)

Auf Chrome ist Methode 3 die beste, dann Methode 1/2 und dann 4/5

Geben Sie hier die Bildbeschreibung ein

In Firefox ist Methode 3 immer noch am besten als Methode 1/2 und dann 4/5

Geben Sie hier die Bildbeschreibung ein

In Opera ist Methode 3 immer noch am besten als Methode 4/5 und dann 1/2

Geben Sie hier die Bildbeschreibung ein

Auf IE 8 folgt es zwar insgesamt langsamer als andere Browser, folgt jedoch immer noch der Reihenfolge von Methode 3, 1,2,4,5.

Geben Sie hier die Bildbeschreibung ein

Insgesamt ist Methode 3 die insgesamt beste Methode, da sie direkt aufgerufen wird und im Gegensatz zu Methode 1/2 nicht mehr als eine Ebene untergeordneter Elemente durchlaufen muss und nicht wie Methode 4/5 analysiert werden muss

Beachten Sie jedoch, dass wir in einigen Fällen Äpfel mit Orangen vergleichen, da Methode 5 alle Kinder anstelle von Kindern der ersten Stufe betrachtet.

Aaron Harun
quelle
Mit identisch meinen Sie, dass beide dieselbe Logik für die Suche verwenden?
Marko
4
Meinen Sie nicht, dass Methode 1 und 2 identisch sind?
Guffa
Danke @Aaron - Ich würde gerne sehen, was die anderen denken. Ich werde Ihre Antwort akzeptieren, wenn alle zustimmen. Prost :)
Marko
@JP, ich meine, es muss etwas länger dauern, bis erkannt wird, dass ein Bereich übergeben wird, um ihn in den $parent.find(".child");Befehl zu übersetzen .
Aaron Harun
2
@Aaron @Marko - Die Tests sind möglicherweise etwas verzerrt, da wir immer den Stammknoten als Kontext verwenden und das Dokument ziemlich groß ist. Trotzdem sehe ich, dass sich 1 und 2 bei den meisten Läufen innerhalb von 20 Ops / Sek. Aneinanderreihen. Im Vergleich zu 1 und 2 ist 4 ungefähr 100-200 Operationen langsamer und 5 ungefähr 400 Operationen langsamer, was verständlich ist, da es alle Nachkommen und nicht nur Kinder durchläuft. Chart - tinyurl.com/25p4dhq
Anurag
13

Methode 1

Kann mit jQuery nicht kürzer und schneller sein. Dieser Aufruf führt direkt zu $(context).find(selector)( Methode 2 aufgrund von Optimierung), die wiederum aufruft getElementById.

Methode 2

Tut das gleiche, aber ohne unnötige interne Funktionsaufrufe.

Methode 3

Die Verwendung children()ist schneller als die Verwendung find(), findet aber natürlich children()nur direkte Kinder des find()Stammelements, während die Suche rekursiv von oben nach unten nach allen untergeordneten Elementen (einschließlich untergeordneter Elemente) erfolgt.

Methode 4

Die Verwendung solcher Selektoren muss langsamer sein. Da sizzle(dies ist die Selektor-Engine von jQuery) von rechts nach links funktioniert , werden zuerst ALLE Klassen abgeglichen, .childbevor überprüft wird, ob sie ein direktes untergeordnetes Element der ID 'parent' sind.

Methode 5

Wie Sie richtig angegeben haben, wird dieser Aufruf $(context).find(selector)aufgrund einiger Optimierungen innerhalb der jQueryFunktion auch einen Aufruf erzeugen , andernfalls könnte er auch den (langsameren) durchlaufen sizzle engine.

jAndy
quelle
2
Sie sprechen nicht über die var $ parent = $ ("# parent"), oder? Ich kann nicht sehen, wie Methode 1 getElementById verwenden kann, wenn das Element eine Klasse hat.
Marko
1
Ich wollte zustimmen, aber in Methode 1 sagt die Dokumentation: Internally, selector context is implemented with the .find() method-Bitte aktualisieren Sie, ich weiß, dass Sie auf den Etiketten des OP verwirrt waren :)
Reigel
@Reigel: true hat das behoben. @ Marko: Parsing #parentstellt eine ID dar. Wenn es sich um eine Klasse handelt, wird sie getElementByIdoffensichtlich nicht verwendet .
jAndy
10

Da es sich um einen alten Beitrag handelt und sich die Dinge mit der Zeit ändern. Ich habe bisher einige Tests mit den letzten Browserversionen durchgeführt und poste sie hier, um Missverständnisse zu vermeiden.

Bei Verwendung von jQuery 2.1 in HTML5- und CSS3-kompatiblen Browsern ändert sich die Leistung.

Hier ist das Testszenario und die Ergebnisse:

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>

Für 100 000 Iterationen bekomme ich also:

JS jQuery-Auswahlstatistiken

(Ich habe sie zu Formatierungszwecken als img hinzugefügt.)

Sie können das Code-Snippet selbst ausführen, um es zu testen;)

Vasil Popov
quelle
Oh! Dann sieht es so aus, als ob .find()es einen tollen Job macht. Weiter benutzen. :)
Andrew Surdu