Einmaliger Event-Listener

Jan Posnick
Jeff Posnick

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

Seien Sie nicht peinlich, wenn Sie dachten, dass addEventListener() nur zwei Parameter benötigt, oder vielleicht einfach immer einen Wert von false hartcodieren, mit dem vagen Verständnis dafür, dass es etwas mit Blasen zu tun hat?

Konfigurierbarere „addEventListener()“-Methode

Die Methode addEventListener() hat sich seit den Anfängen des Webs erheblich verbessert. Die neue Funktionalität wird über eine erweiterte Version dieses dritten Parameters konfiguriert. Jüngste Änderungen an der Definition der Methode ermöglichen es Entwicklern, zusätzliche Optionen über ein Konfigurationsobjekt bereitzustellen. Gleichzeitig bleiben sie abwärtskompatibel, wenn ein boolescher Parameter vorhanden ist oder keine Option angegeben ist.

In Chrome 55 wird jetzt neben den Optionen passive (in Chrome 51 implementiert) und capture (in Chrome 49 implementiert) auch die Option once in diesem Konfigurationsobjekt unterstützt. Beispiel:

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

Sie können diese Optionen je nach Anwendungsfall beliebig kombinieren.

Die Vorteile des Aufräumens

Das ist also die Syntax für die Verwendung der neuen Option once, aber was bringt das? Kurz gesagt: Sie erhalten einen Event-Listener, der auf "One and Done"-Anwendungsfälle zugeschnitten ist.

Standardmäßig bleiben Event-Listener nach dem ersten Aufruf bestehen. Dies ist bei einigen Ereignistypen sinnvoll, z. B. bei Schaltflächen, auf die mehrmals geklickt werden kann. Für andere Anwendungen ist ein Event-Listener jedoch nicht erforderlich und kann zu unerwünschtem Verhalten führen, wenn Sie einen Callback haben, der nur einmal ausgeführt werden muss. Hygienic Developer hatten schon immer die Möglichkeit, removeEventListener() zu verwenden, um Dinge explizit nach Mustern wie den folgenden zu bereinigen:

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

Der entsprechende Code, der den neuen once-Parameter verwendet, ist übersichtlicher und zwingt Sie nicht dazu, den Namen des Ereignisses (im vorherigen Beispiel event.type) oder einen Verweis auf die Callback-Funktion (cb) im Auge zu behalten:

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

Durch das Bereinigen der Event-Handler kann auch eine höhere Speichereffizienz erzielt werden. Dazu wird der mit der Callback-Funktion verknüpfte Bereich gelöscht, sodass alle in diesem Bereich erfassten Variablen automatisch bereinigt werden. Hier ist ein Beispiel, bei dem dies einen Unterschied machen würde:

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 Callback load des Event-Listeners nach der Ausführung im Bereich, auch wenn er nie wieder verwendet wird. Da die Variable data innerhalb des Callbacks verwendet wird, bleibt sie ebenfalls im Bereich und wird nie automatisch bereinigt. Würde der Callback jedoch über den Parameter once entfernt, sind sowohl die Funktion selbst als auch alle Inhalte, die über ihren Bereich aktiv bleiben, potenziell Kandidaten für die automatische Speicherbereinigung.

Unterstützte Browser

In Chrome (ab Version 55, Firefox 50 und höher) und der Technologievorschau (ab Version 7) von Safari wird die Option once nativ unterstützt.

Viele JavaScript-UI-Bibliotheken bieten praktische Methoden zum Erstellen von Event-Listenern. Einige haben Tastenkombinationen zum Definieren einmaliger Ereignisse. Die wichtigste davon ist die one()-Methode von jQuery. Ein Polyfill ist auch als Teil der dom4-Bibliothek von Andrea Giammarchi verfügbar.

Vielen Dank

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