Gute Möglichkeiten zur Verbesserung der Leistung von jQuery Selector?

74

Ich suche nach einer Möglichkeit, die Selektorleistung eines jQuery-Aufrufs zu verbessern. Speziell solche Dinge:

Ist $("div.myclass")schneller als$(".myclass")

Ich würde denken, es könnte sein, aber ich weiß nicht, ob jQuery klug genug ist, um die Suche zuerst nach dem Tag-Namen usw. einzuschränken. Hat jemand Ideen, wie eine jQuery-Auswahlzeichenfolge für die beste Leistung formuliert werden kann?

JC Grubbs
quelle

Antworten:

36

Es besteht kein Zweifel, dass das Filtern nach dem Tag-Namen zuerst viel schneller ist als das Filtern nach dem Klassennamen.

Dies ist so lange der Fall, bis alle Browser getElementsByClassName nativ implementieren, wie dies bei getElementsByTagName der Fall ist.

Kamens
quelle
Aber selbst wenn der Browser diese Funktion implementiert, wäre es immer noch schneller, nach dem Tag-Namen zu filtern, oder?
Hoffmann
Ich habe componenthouse.com/article-19 von Jeffs Antwort aktualisiert , um die neueste jQuery zu verwenden. Es scheint, dass A und B ab dem zweiten Test die gleiche Leistung in Opera 10 und Firefox 3.5 haben. Ich konnte es auf IE8 nicht zum Laufen bringen (ich habe aber nicht viel versucht). Es scheint also, dass ich mich in meinem vorherigen Kommentar geirrt habe.
Hoffmann
@offmann, wahrscheinlich nicht. Wenn wir annehmen, dass diese beiden Funktionen mit B-Bäumen implementiert sind, verstehe ich nicht, warum getElementsByClassName langsamer wäre ... Sie müssten den Index noch erstellen, bevor Sie diese Funktion verwenden können ...
Evan Carroll
@AlienWebguy: Der Punkt dieser Antwort ist, dass einige Browser nicht unterstützen getElementsByClassName, was bedeutet, dass jedes Element auf der Seite für die Klasse getestet werden muss. Denken Sie daran, dass diese Antwort auch in '08 gegeben wurde. ; o)
user113716
1
@AlienWebguy: Ihr Test repräsentiert eine große Seite mit vielen DOM-Elementen nicht genau. Ihr Test ist schneller aufgrund eines einfacheren Filtersatzes und nicht aufgrund einer schnelleren Suche.
Aren
14

In einigen Fällen können Sie eine Abfrage beschleunigen, indem Sie ihren Kontext einschränken. Wenn Sie eine Elementreferenz haben, können Sie diese als zweites Argument übergeben, um den Umfang der Abfrage einzuschränken:

$(".myclass", a_DOM_element);

sollte schneller sein als

$(".myclass");

Wenn Sie bereits ein_DOM_element haben und es erheblich kleiner als das gesamte Dokument ist.

Matthew Crumley
quelle
2
Wie ich mich erinnere, $('.myclass', a_DOM_element)übersetzt jQuery in / Aufrufe, $(a_DOM_element).find('.myclass')sodass es möglicherweise etwas schneller ist, es einfach zu verwenden, find()als wie in Ihrem ersten Beispiel einen Auswahlkontext einzurichten .
David sagt, Monica
5

Wie Reid oben sagte, arbeitet jQuery von unten nach oben. Obwohl

das heißt $('#foo bar div')ist viel langsamer als$('bar div #foo')

Das ist nicht der Punkt. Wenn Sie dies #foogetan hätten, würden Sie sowieso nichts davor in die Auswahl stellen, da IDs eindeutig sein müssen.

Der Punkt ist:

  • wenn man etwas von einem Element mit einer ID werden dann die Teilauswahl wählen später und erst dann verwenden .find, .childrenetc .:$('#foo').find('div')
  • Ihre ganz links (erste) Teil des Wählers kann weniger effizient Skalierung auf der äußersten rechten (letzten) Teil sein , das sollte die effizienteste sein - das heißt , wenn Sie eine ID - Marke haben nicht sicher , Sie suchen , $('div.common[slow*=Search] input.rare')anstatt $('div.rare input.common[name*=slowSearch]')- seit dieser isn‘ t immer zutreffend Stellen Sie sicher, dass Sie die Auswahlreihenfolge durch entsprechende Aufteilung erzwingen.
Philipp
quelle
5

Um zu verstehen, was schneller ist, müssen Sie verstehen, wie der CSS-Parser funktioniert.

Der Selektor, den Sie übergeben, wird mit RegExp in erkennbare Teile aufgeteilt und dann Stück für Stück verarbeitet.

Einige Selektoren wie ID und TagName verwenden die native Implementierung des Browsers, die schneller ist. Während andere wie Klasse und Attribute separat programmiert werden und daher viel langsamer sind, müssen ausgewählte Elemente durchlaufen und jeder Klassenname überprüft werden.

Also ja, um deine Frage zu beantworten:

$ ('tag.class') ist schneller als nur $ ('. class'). Warum? Im ersten Fall verwendet jQuery die native Browser-Implementierung, um die Auswahl auf die Elemente zu filtern, die Sie benötigen. Erst dann wird die langsamere .class-Implementierung gestartet, die auf das herunterfiltert, wonach Sie gefragt haben.

Im zweiten Fall verwendet jQuery seine Methode, um jedes einzelne Element durch Abrufen der Klasse zu filtern.

Dies breitet sich weiter aus als jQuery, da alle Javascript-Bibliotheken darauf basieren. Die einzige andere Option ist die Verwendung von xPath, die derzeit jedoch nicht von allen Browsern unterstützt wird.

Dmitri Farkov
quelle
4

So steigern Sie die Leistung Ihrer jQuery-Selektoren:

  • Wann immer möglich mit #id auswählen ( Leistungstestergebnisse ~ 250 schneller)
  • Geben Sie den Umfang Ihrer Auswahl an ( $('.select', this))
jQuery Lover
quelle
3

Ich möchte einen Hinweis hinzufügen, dass in 99% der Web-Apps, selbst bei Ajax-Apps, die Verbindungsgeschwindigkeit und die Reaktion des Webservers eher die Leistung Ihrer App als die von Javascript beeinflussen. Ich sage nicht, dass Sie absichtlich langsamen Code schreiben sollten oder dass es nicht gut ist, sich im Allgemeinen darüber im Klaren zu sein, welche Dinge wahrscheinlich schneller sind als andere.

Aber ich frage mich, ob Sie versuchen, ein Problem zu lösen, das noch nicht wirklich existiert, oder ob Sie für etwas optimieren, das sich in naher Zukunft ändern könnte (z. B. wenn mehr Leute einen Browser verwenden, der getElementsByClassName()Funktionen unterstützt (siehe oben), wodurch Ihr optimierter Code tatsächlich langsamer ausgeführt wird.

Joel Coehoorn
quelle
3

Ein weiterer Ort, an dem Sie nach Leistungsinformationen suchen können, ist die Seite Leistungsanalyse der Selektoren von Hugo Vidal Teixeira.

http://www.componenthouse.com/article-19

Dies führt zu einer guten Geschwindigkeitsreduzierung für Selektor nach ID, Selektor nach Klasse und Tag-Name mit Präfix-Präfix.

Die schnellste Auswahl nach ID war: $ ("# id")

Der schnellste Selektor nach Klasse war: $ ('tag.class')

Das Präfixieren nach Tag half also nur bei der Auswahl nach Klasse!

Evan Moran
quelle
0

Ich war auf einigen der jQuery-Mailinglisten und nach dem, was ich dort gelesen habe, filtern sie höchstwahrscheinlich nach Tag-Namen und Klassennamen (oder umgekehrt, wenn es schneller war). Sie sind besessen von Geschwindigkeit und würden alles verwenden, um ein wenig Leistung zu erzielen.

Ich würde mir sowieso keine allzu großen Sorgen machen, wenn Sie diesen Selektor nicht tausende Male pro Sekunde ausführen.

Wenn Sie wirklich besorgt sind, versuchen Sie es mit einem Benchmarking und finden Sie heraus, welches schneller ist.

Ryan Doherty
quelle
0

Verwenden Sie die Sequential-Bibliothek von Oliver Steele, um Methoden im Laufe der Zeit aufzurufen, anstatt alle gleichzeitig.

http://osteele.com/sources/javascript/sequential/

Mit der Methode "eventuell" können Sie eine Methode nach einer bestimmten Zeitspanne ab ihrem ersten Aufruf aufrufen. Mit der Methode "sequentiell" können Sie mehrere Aufgaben über einen bestimmten Zeitraum in die Warteschlange stellen.

Sehr hilfreich!

Evan Moran
quelle
0

Ein guter Tipp aus einer Frage, die ich gestellt habe: Verwenden Sie nach Möglichkeit Standard-CSS-Selektoren . Dadurch kann jQuery die Selectors-API verwenden . Nach Tests von John Resig führt dies zu einer nahezu nativen Leistung für Selektoren. Funktionen wie :has()und :contains()sollten vermieden werden.

Aus meiner Forschung wurde die Unterstützung für die Selectors-API mit jQuery 1.2.7, Firefox 3.1, IE 8, Opera 10, Safari 3.1 eingeführt.

Alex Angas
quelle
0

Wenn ich mich nicht irre, ist jQuery auch eine Bottom-Up-Engine. Das heißt, es $('#foo bar div')ist viel langsamer als $('bar div #foo'). $('#foo a')Gehen Sie beispielsweise alle aElemente auf der Seite durch und prüfen Sie, ob sie einen Vorfahren von haben #foo, was diesen Selektor immens ineffizient macht.

Resig hat sich möglicherweise bereits für dieses Szenario optimiert (es würde mich nicht überraschen, wenn er es tun würde - ich glaube, er hat es in seiner Sizzle-Engine getan, aber ich bin nicht 100% sicher.)

Reid
quelle
0

Ich glaube, dass die Auswahl zuerst nach ID immer schneller ist:

$("#myform th").css("color","red");

sollte schneller sein als

$("th").css("color","red");

Ich frage mich jedoch, wie viel Verkettung hilft, wenn ich mit der ID beginne. Ist das

$("#myform").find("th").css("color","red")
.end().find("td").css("color","blue");

schneller als das?

$("#myform th").css("color","red");
$("#myform td").css("color","blue");
Lawrence
quelle
Nach meiner Erfahrung ist $ ("# myform"). Find ("th") auch schneller als $ ("# myform th"), da erstere direkt an die native getElementByID des Browsers delegiert. Die Verkettung hilft auch, aber im Wesentlichen ist der Overhead die Kosten für einen zweiten getElementByID-Aufruf, der normalerweise winzig ist.
Peakxu
sizzle, die Auswahlmaschine von jQuery funktioniert von rechts nach links. Also dein erstes Beispiel: $ ("# myform th"). Css ("color", "red"); findet zuerst jedes th auf der Seite. Dann durchläuft es diese Ths und betrachtet die Eltern für jedes, bis es ein Element mit der ID von myForm findet. Theoretisch dann Ihr zweites Beispiel: $ ("th"). CSS ("color", "red"); sollte schneller sein als deine erste, da das nur über die th iteriert und ihre Eltern nicht inspiziert.
Chris Spittles