Woher kommt das?
Als ich jQuery zum ersten Mal lernte, habe ich normalerweise Ereignisse wie diese angehängt:
$('.my-widget a').click(function() {
$(this).toggleClass('active');
});
Nachdem ich mehr über die Auswahlgeschwindigkeit und die Ereignisdelegierung erfahren habe, habe ich an mehreren Stellen gelesen, dass "die jQuery-Ereignisdelegierung Ihren Code schneller macht". Also fing ich an, Code wie folgt zu schreiben:
$('.my-widget').on('click','a',function() {
$(this).toggleClass('active');
});
Dies war auch die empfohlene Methode, um das Verhalten des veralteten .live () -Ereignisses zu replizieren. Das ist mir wichtig, da viele meiner Websites ständig Widgets dynamisch hinzufügen / entfernen. Das obige Verhalten verhält sich jedoch nicht genau wie .live (), da nur Elemente, die dem bereits vorhandenen Container '.my-widget' hinzugefügt wurden, das Verhalten erhalten. Wenn ich nach dem Ausführen dieses Codes dynamisch einen weiteren HTML-Block hinzufüge, erhalten diese Elemente die an sie gebundenen Ereignisse nicht. So was:
setTimeout(function() {
$('body').append('<div class="my-widget"><a>Click does nothing</a></div>');
}, 1000);
Was ich erreichen möchte:
- Das alte Verhalten von .live () // bedeutet, dass Ereignisse an noch nicht vorhandene Elemente angehängt werden
- die Vorteile von .on ()
- schnellste Leistung zum Binden von Ereignissen
- Einfache Möglichkeit, Ereignisse zu verwalten
Ich füge jetzt alle Ereignisse wie folgt hinzu:
$(document).on('click.my-widget-namespace', '.my-widget a', function() {
$(this).toggleClass('active');
});
Welches scheint alle meine Ziele zu erfüllen. (Ja, es ist aus irgendeinem Grund im IE langsamer, keine Ahnung warum?) Es ist schnell, da nur ein einzelnes Ereignis an ein einzelnes Element gebunden ist und der sekundäre Selektor nur ausgewertet wird, wenn das Ereignis eintritt (bitte korrigieren Sie mich, wenn dies hier falsch ist). Der Namespace ist fantastisch, da er das Umschalten des Ereignis-Listeners erleichtert.
Meine Lösung / Frage
Ich fange an zu denken, dass jQuery-Ereignisse immer an $ (document) gebunden sein sollten.
Gibt es einen Grund, warum Sie dies nicht tun möchten?
Könnte dies als bewährte Methode angesehen werden? Wenn nicht, warum?
Wenn Sie das Ganze gelesen haben, danke. Ich freue mich über alle Rückmeldungen und Erkenntnisse.
Annahmen:
- Verwenden von jQuery, das
.on()
// mindestens Version 1.7 unterstützt - Sie möchten, dass das Ereignis zu dynamisch hinzugefügten Inhalten hinzugefügt wird
Lesungen / Beispiele:
Antworten:
Nein - Sie sollten NICHT alle delegierten Ereignishandler an das
document
Objekt binden . Dies ist wahrscheinlich das Szenario mit der schlechtesten Leistung, das Sie erstellen können.Zunächst einmal beschleunigt die Ereignisdelegierung Ihren Code nicht immer. In einigen Fällen ist dies vorteilhaft und in einigen Fällen nicht. Sie sollten die Ereignisdelegierung verwenden, wenn Sie tatsächlich eine Ereignisdelegierung benötigen und wenn Sie davon profitieren. Andernfalls sollten Sie Ereignishandler direkt an die Objekte binden, in denen das Ereignis auftritt, da dies im Allgemeinen effizienter ist.
Zweitens sollten Sie NICHT alle delegierten Ereignisse auf Dokumentebene binden. Dies ist genau der Grund, warum dies
.live()
veraltet war, da dies sehr ineffizient ist, wenn viele Ereignisse auf diese Weise gebunden sind. Für die Behandlung delegierter Ereignisse ist es VIEL effizienter, sie an das nächste übergeordnete Element zu binden, das nicht dynamisch ist.Drittens funktionieren nicht alle Ereignisse oder alle Probleme können mit der Delegierung gelöst werden. Wenn Sie beispielsweise Schlüsselereignisse auf einem Eingabesteuerelement abfangen und die Eingabe ungültiger Schlüssel in das Eingabesteuerelement blockieren möchten, können Sie dies nicht mit der Behandlung delegierter Ereignisse tun, da dies bereits der Fall ist, wenn das Ereignis an den delegierten Handler weitergeleitet wird wurde von der Eingabesteuerung verarbeitet und es ist zu spät, um dieses Verhalten zu beeinflussen.
Hier sind Zeiten, in denen eine Ereignisdelegierung erforderlich oder vorteilhaft ist:
Um dies ein wenig besser zu verstehen, muss man verstehen, wie von jQuery delegierte Ereignishandler funktionieren. Wenn Sie so etwas nennen:
Es installiert einen generischen jQuery-Ereignishandler für das
#myParent
Objekt. Wenn ein Klickereignis zu diesem delegierten Ereignishandler sprudelt, muss jQuery die Liste der an dieses Objekt angehängten delegierten Ereignishandler durchgehen und prüfen, ob das Ursprungselement für das Ereignis mit einem der Selektoren in den delegierten Ereignishandlern übereinstimmt.Da Selektoren ziemlich involviert sein können, bedeutet dies, dass jQuery jeden Selektor analysieren und dann mit den Merkmalen des ursprünglichen Ereignisziels vergleichen muss, um festzustellen, ob er mit jedem Selektor übereinstimmt. Dies ist keine billige Operation. Es ist keine große Sache, wenn es nur eine davon gibt. Wenn Sie jedoch alle Ihre Selektoren auf das Dokumentobjekt setzen und Hunderte von Selektoren mit jedem einzelnen Bubble-Ereignis zu vergleichen waren, kann dies die Leistung der Ereignisbehandlung ernsthaft beeinträchtigen.
Aus diesem Grund möchten Sie Ihre delegierten Ereignishandler so einrichten, dass sich ein delegierter Ereignishandler so nah wie möglich am Zielobjekt befindet. Dies bedeutet, dass weniger Ereignisse durch jeden delegierten Ereignishandler sprudeln und somit die Leistung verbessern. Das Einfügen aller delegierten Ereignisse in das Dokumentobjekt ist die schlechteste Leistung, da alle Bubble-Ereignisse alle delegierten Ereignishandler durchlaufen und gegen alle möglichen delegierten Ereignisselektoren ausgewertet werden müssen. Genau aus diesem Grund
.live()
wird dies abgelehnt, da dies.live()
der Fall war und sich als sehr ineffizient erwiesen hat.So erzielen Sie eine optimierte Leistung:
quelle
$(document).on('click', '[myCustomAttr]', function () { ... });
?document
, oder binden an spezifische Auswahl aufpage:load
und unbind dieser Ereignisse aufpage:after-remove
? HmmmDie Ereignisdelegierung ist eine Technik zum Schreiben Ihrer Handler, bevor das Element tatsächlich im DOM vorhanden ist. Diese Methode hat ihre eigenen Nachteile und sollte nur verwendet werden, wenn Sie solche Anforderungen haben.
Wann sollten Sie die Ereignisdelegierung verwenden?
Warum sollten Sie keine Ereignisdelegierung verwenden?
PS: Selbst für dynamische Inhalte müssen Sie keine Ereignisdelegierungsmethode verwenden, wenn Sie den Handler binden, nachdem die Inhalte in DOM eingefügt wurden. (Wenn der dynamische Inhalt hinzugefügt wird, wird er nicht häufig entfernt / erneut hinzugefügt.)
quelle
Anscheinend wird jetzt tatsächlich eine Ereignisdelegation empfohlen. Zumindest für Vanille js.
https://gomakethings.com/why-event-delegation-is-a-better-way-to-listen-for-events-in-vanilla-js/
"Webleistung # Es fühlt sich an, als würde das Abhören jedes Klicks im Dokument die Leistung beeinträchtigen, aber es ist tatsächlich leistungsfähiger als eine Reihe von Ereignis-Listenern für einzelne Elemente."
quelle
Ich möchte der Antwort von jfriend00 einige Bemerkungen und Gegenargumente hinzufügen. (meistens nur meine Meinung basierend auf meinem Bauchgefühl)
Zwar ist die Leistung möglicherweise etwas besser, wenn Sie sich nur für ein einzelnes Element registrieren und ein Ereignis durchführen. Ich glaube jedoch, dass dies nicht die Skalierbarkeitsvorteile der Delegierung beeinträchtigt. Ich glaube auch, dass Browser dies immer effizienter handhaben (werden), obwohl ich keinen Beweis dafür habe. Meiner Meinung nach ist Eventdelegation der richtige Weg!
Ich stimme dem irgendwie zu. Wenn Sie zu 100% sicher sind, dass ein Ereignis nur innerhalb eines Containers auftritt, ist es sinnvoll, das Ereignis an diesen Container zu binden, aber ich würde trotzdem dagegen sprechen, Ereignisse direkt an das auslösende Element zu binden.
Das ist einfach nicht wahr. Bitte beachten Sie diesen CodePen: https://codepen.io/pwkip/pen/jObGmjq
Es zeigt, wie Sie verhindern können, dass ein Benutzer tippt, indem Sie das Tastendruckereignis im Dokument registrieren.
Ich möchte mit diesem Zitat von https://ehsangazar.com/optimizing-javascript-event-listeners-for-performance-e28406ad406c antworten
Event delegation promotes binding as few DOM event handlers as possible, since each event handler requires memory. For example, let’s say that we have an HTML unordered list we want to bind event handlers to. Instead of binding a click event handler for each list item (which may be hundreds for all we know), we bind one click handler to the parent unordered list itself.
Wenn Sie nach googeln suchen, erhalten Sie
performance cost of event delegation google
mehr Ergebnisse zugunsten der Ereignisdelegierung.Wo ist das dokumentiert? Wenn das stimmt, scheint jQuery die Delegierung sehr ineffizient zu behandeln, und dann sollten meine Gegenargumente nur auf Vanilla JS angewendet werden.
Dennoch: Ich würde gerne eine offizielle Quelle finden, die diese Behauptung stützt.
:: EDIT ::
Scheint, als würde jQuery tatsächlich Ereignisblasen auf sehr ineffiziente Weise ausführen (da sie IE8 unterstützen). Https://api.jquery.com/on/#event-performance
Die meisten meiner Argumente hier gelten also nur für Vanilla JS und moderne Browser.
quelle