Wie wird der jQuery-Selektor $(‘#foo a’) ausgewertet?

Lesezeit: 5 Minuten

Benutzer-Avatar
Afshin Mehrabani

Als Beispiel für jQuery-Code (https://coderwall.com/p/7uchvg), Ich habe gelesen, dass der Ausdruck $('#foo a'); verhält sich so:

Finde jeden a auf der Seite und dann filtern a Innerhalb #foo.

Und es sieht nicht effizient aus.

Ist das korrekt? Und wenn ja, wie sollten wir das besser machen?

  • @undefined Bitte schau dir das an: coderwall.com/p/7uchvg

    – Afshin Mehrabani

    3. Dezember 2012 um 7:13 Uhr

  • Zum Glück wurde der von Ihnen verlinkte Beitrag in seinen Kommentaren korrigiert.

    – LarsH

    3. Dezember 2012 um 16:06 Uhr

Das ist richtig – Sizzle (die Selektor-Engine von jQuery) verhält sich so genauso wie CSS-Selektoren. CSS- und Sizzle-Selektoren sind von rechts nach links ausgewertetund so #foo a wird alles finden a Knoten, und filtern Sie diese dann nach Knoten, die von absteigen #foo.

Sie verbessern dies, indem Sie sicherstellen, dass Ihre Blattselektoren eine hohe Spezifität aufweisen, normalerweise indem Sie ihnen eine Klasse oder ID zuweisen.

  • Sizzle könnte, aber … auf Chrome, dieser jsperf zeigt an $('#id span') ist 10x schneller als $('span')was meiner Meinung nach nicht mit dem beschriebenen Algorithmus übereinstimmt.

    – Amadan

    3. Dezember 2012 um 7:19 Uhr

  • Das kann daran liegen, dass jQuery mehrere DOM-Knoten pro Lauf in der dekorieren muss span Fall (mehr als der Test läuft), und nur einer in der #id span Fall. Schauen Sie sich dieses jsperf an – jsperf.com/does-id-el-find-all-els-first/3 – Wenn Sie LTR mit RTL vergleichen, ist RTL schneller.

    – Chris Heil

    3. Dezember 2012 um 7:33 Uhr


  • Es ist auch bemerkenswert, dass Sie die Sizzle-Engine umgehen können, indem Sie eine bestimmte JQuery-Funktion wie z find() oder children(). Also statt $("#foo a") Sie können verwenden $("#foo").find("a")

    – Matanya

    3. Dezember 2012 um 7:34 Uhr


  • @Matanya – Yurys jsperf-Testfall ist in der Tat eine brillante Demonstration dessen. So geht es viel schneller!

    – Chris Heil

    3. Dezember 2012 um 7:35 Uhr

  • @YuryTarabanko: Danke, das war aufschlussreich.

    – Amadan

    3. Dezember 2012 um 14:14 Uhr

Benutzer-Avatar
Andries

wie sollen wir das besser machen?

Verwenden Sie den Kontextparameter von jQuery.

$('a', '#foo');

Jetzt sucht jQuery alle Anker im Kontext des Elements mit der ID: foo.

In Ihrer Abfrage wird der Kontext standardmäßig auf document gesetzt, wenn er weggelassen wird:

$('#foo a'); == $('#foo a', document); 

In diesem Fall ist Ihre Abfrage tatsächlich nicht effizient.

Sie könnten einen Blick darauf werfen bei diesem Artikel.

  • Sie können es auch auf jsperf.com messen jsperf.com/popular –> einige Beispiele

    – Kokizzu

    3. Dezember 2012 um 15:44 Uhr

  • Sie sollten immer ein DOM-Element als Kontextargument übergeben, keinen Selektor. jsperf.com/jquery-context-test

    – Danwellmann

    5. April 2014 um 9:03 Uhr

Es stimmt zwar, dass Sizzle eine Engine von rechts nach links ist (was der gleichen Art und Weise entspricht, wie CSS interpretiert wird), aber es stimmt nicht, dass der spezifische Selektor in Ihrem Beispiel alle Ankerelemente auf der Seite auswählen und dann ihre übergeordneten Elemente filtern würde mit der ID von “foo” übereinstimmen. Sizzle optimiert tatsächlich jeden Selektor, der mit einer ID beginnt, und verwendet diesen als Kontext für die gesamte Auswahl, anstatt das Dokument zu verwenden. Mit anderen Worten, der von Ihnen gewählte Selektor bedeutet im Grunde Folgendes:

document.getElementById("foo").getElementsByTagName("a")

Wirklich, das ist überhaupt kein schlechter Selektor.

Angesichts der anderen Dinge, die jQuery tun muss (einschließlich des Schleifens über die Elemente, um sie mit der jQuery-Instanz zusammenzuführen), ist jQuery(“#foo”).find(“a”) jedoch immer am schnellsten, da jQuery eine jQuery implementiert Objekterstellungsverknüpfung für Nur-ID-Selektoren, und dann führt es die Suche aus, die von #foo verwurzelt ist.

Mit anderen Worten, Sizzle selbst ist nicht viel anders, wenn es darum geht Sizzle("#foo a") und Sizzle("a", document.getElementById("foo"))aber jQuery("#foo").find... wird wegen der eigenen ID-Verknüpfung von jQuery schneller sein.

Übrigens gehen meine Bemerkungen zu Sizzle davon aus, dass querySelectorAll nicht verwendet wird. Wenn dies der Fall ist, leitet Sizzle es einfach an qsa weiter, was immer noch nicht so schnell ist wie die Verwendung der ID-Verknüpfung von jQuery.

Benutzer-Avatar
Christoph

Sie können find () verwenden, um Ihre Auswahlreihenfolge genauer zu steuern:

$('#foo').find('a');

Dies ist natürlich bei komplexeren Selektoren beeindruckender, bei denen Sie find() und filter() verketten können.

Für das Protokoll $('#foo').find('a') === $('a','#foo')

[Update] ok, ich habe später gemerkt, dass es genau das ist, was dein Link sagt …

Die jQuery-Selektor-Engine (Sizzle) wurde letztes Jahr überarbeitet, detaillierte Erklärungen finden Sie hier:
http://www.wordsbyf.at/2011/11/23/selectors-selectoring/

Benutzer-Avatar
Murali N

Anstatt mit zu filtern a Innerhalb #foo Elemente, hängen Sie einfach eine Klasse an a Elemente und bekommen a Elemente mit Klasse wie $("a.class");. Dies wäre effizienter.

Benutzer-Avatar
drzaus

Noch ein “selbst ausprobieren”:

  1. jsperf für verschiedene Selektoren für 10000 Elemente
  2. jsperf für verschiedene Selektoren für 300 Elemente
  3. jsperf für verschiedene Selektoren auf einem “repräsentativeren DOM”

Scheint kein großer Unterschied zu einem “flachen” DOM ​​(1 & 2) zu sein, aber die Leistung variiert viel stärker mit einem verschachtelten DOM.

Beachten Sie auch, dass einige der Testfälle nicht die richtigen Elemente auswählen (z $('.a') vs $('.a', context)), aber ich habe sie nur zum Vergleich aus den ursprünglichen Tests gelassen.

Benutzer-Avatar
Herr H

Dieses Beispiel ruft alle Ankerelemente ab a in einem Element namens fooum jedes a auf der Seite zu finden und dann ein innerhalb von #foo zu filtern, wie Sie möchten, sollten Sie auswählen a #foo

$("a #foo");

Dadurch werden alle abgerufen foo Elemente drin a Elemente.

  • “a #foo” ist ziemlich suboptimal. Sie können nur 1 Element mit haben id="foo".

    – Juri Tarabanko

    3. Dezember 2012 um 7:23 Uhr

  • Ich verstehe nicht, warum diese Antwort so viele Ablehnungen erhalten hat. Ich glaube, Herr H. hat die Frage falsch verstanden, aber die Frage war schlecht formuliert. “Filter a Innerhalb #foo” ist kaum Standardgrammatik.

    – LarsH

    3. Dezember 2012 um 19:14 Uhr

1256850cookie-checkWie wird der jQuery-Selektor $(‘#foo a’) ausgewertet?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy