Einmaliger Event-Listener

Quiz: Welchen Zweck erfüllt der dritte Parameter, der an addEventListener() übergeben wird?

Keine Sorge, wenn Sie dachten, dass für addEventListener() nur zwei Parameter erforderlich sind, oder immer den Wert false hartcodiert haben, weil Sie nur ungefähr wussten, dass es etwas mit… Bubbles zu tun hat?

Eine konfigurierbarere addEventListener()

Die addEventListener()-Methode hat sich seit den Anfängen des Webs stark weiterentwickelt. Die neuen Funktionen werden über eine optimierte Version dieses dritten Parameters konfiguriert. Durch die jüngsten Änderungen an der Definition der Methode können Entwickler zusätzliche Optionen über ein Konfigurationsobjekt angeben und gleichzeitig die Abwärtskompatibilität beibehalten, wenn ein boolescher Parameter vorhanden ist oder eine Option nicht angegeben ist.

In Chrome 55 wird die Option once in diesem Konfigurationsobjekt unterstützt. Außerdem sind die Optionen passive (in Chrome 51 implementiert) und capture (in Chrome 49 implementiert) verfügbar. Beispiel:

element.addEventListener('click', myClickHandler, {
    once: true,
    passive: true,
    capture: true
});

Sie können diese Optionen je nach Anwendungsfall kombinieren.

Vorteile des Aufräumens nach dem Test

Das ist die Syntax für die neue Option once. Was bringt sie Ihnen? Kurz gesagt: Sie erhalten einen Ereignis-Listener, der auf Anwendungsfälle zugeschnitten ist, die nur einmal ausgeführt werden.

Standardmäßig bleiben Ereignis-Listener nach dem ersten Aufruf erhalten. Das ist bei einigen Ereignistypen sinnvoll, z. B. bei Schaltflächen, auf die mehrmals geklickt werden kann. Bei anderen Verwendungszwecken ist es jedoch nicht erforderlich, dass ein Ereignis-Listener aktiv bleibt. Dies kann zu unerwünschtem Verhalten führen, wenn ein Rückruf nur einmal ausgeführt werden muss. Hygienische Entwickler hatten schon immer die Möglichkeit, removeEventListener() zu verwenden, um Dinge explizit zu bereinigen, und dabei Muster wie die folgenden zu verwenden:

element.addEventListener('click', function cb(event) {
    // ...one-time handling of the click event...
    event.currentTarget.removeEventListener(event.type, cb);
});

Der entsprechende Code mit dem neuen Parameter once ist übersichtlicher und Sie müssen sich nicht mehr den Namen des Ereignisses (event.type im vorherigen Beispiel) oder einen Verweis auf die Rückruffunktion (cb) merken:

element.addEventListener('click', function(event) {
    // ...one-time handling of the click event...
}, {once: true});

Durch die Bereinigung Ihrer Ereignishandler können Sie auch die Speichereffizienz verbessern, indem Sie den Gültigkeitsbereich löschen, der mit der Rückruffunktion verknüpft ist. Dadurch können alle Variablen, die in diesem Gültigkeitsbereich erfasst wurden, vom Garbage Collector beseitigt werden. Hier ein Beispiel, in dem das einen Unterschied macht:

function setUpListeners() {
    var data = ['one', 'two', '...etc.'];

    window.addEventListener('load', function() {
    doSomethingWithSomeData(data);
    // data is now part of the callback's scope.
    });
}

Standardmäßig bleibt der Rückruf des load-Ereignislisteners im Gültigkeitsbereich, auch wenn er nie wieder verwendet wird. Da die Variable data im Rückruf verwendet wird, bleibt sie auch im Gültigkeitsbereich und wird nie vom Garbage Collector erfasst. Wenn der Callback jedoch über den Parameter once entfernt wird, sind sowohl die Funktion selbst als auch alles, was über ihren Gültigkeitsbereich aktiv gehalten wird, potenziell Kandidaten für die Garbage Collection.

Unterstützte Browser

Chrome ab Version 55, Firefox ab Version 50 und die Technologievorschau 7 von Safari bieten native Unterstützung für die Option once.

Viele JavaScript-UI-Bibliotheken bieten praktische Methoden zum Erstellen von Ereignis-Listenern und einige haben Tastenkürzel zum Definieren einmaliger Ereignisse. Die bekannteste davon ist die one()-Methode von jQuery. Es ist auch eine Polyfill-Version verfügbar, die Teil der dom4-Bibliothek von Andrea Giammarchi ist.

Vielen Dank

Vielen Dank an Ingvar Stepanyan für das Feedback zum Beispielcode in diesem Beitrag.