Er was eens een gebeurtenisluisteraar

Popquiz: wat is het doel van de derde parameter die wordt doorgegeven aan addEventListener() ?

Schaam je niet als je dacht dat addEventListener() slechts twee parameters nodig had, of misschien gewoon altijd een waarde van false hardcodeerde, met een vaag begrip dat het iets te maken heeft met... bubbels?

Een beter configureerbare addEventListener()

De methode addEventListener() heeft een lange weg afgelegd sinds de begindagen van het web, en de nieuwe functionaliteit ervan wordt geconfigureerd via een verbeterde versie van die derde parameter. Recente wijzigingen in de definitie van de methode stellen ontwikkelaars in staat extra opties te bieden via een configuratieobject , terwijl ze achterwaarts compatibel blijven als er een Booleaanse parameter is of als een optie niet is opgegeven.

We zijn blij om aan te kondigen dat Chrome 55 ondersteuning toevoegt voor de once optie in dat configuratieobject, naast de passive ( geïmplementeerd in Chrome 51 ) en capture ( geïmplementeerd in Chrome 49 ). Bijvoorbeeld:

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

U kunt deze opties mixen en matchen, afhankelijk van uw eigen gebruiksscenario.

De voordelen van zelf opruimen

Dus dat is de syntaxis voor het gebruik van de nieuwe once optie, maar wat levert dat op? Kortom, het biedt u een gebeurtenislistener die is toegesneden op 'eenmalige' gebruiksscenario's.

Standaard blijven gebeurtenislisteners bestaan ​​nadat ze voor de eerste keer zijn aangeroepen, wat u bij sommige soorten gebeurtenissen wilt, bijvoorbeeld knoppen waarop meerdere keren kan worden geklikt. Voor ander gebruik is het echter niet nodig dat er een gebeurtenislistener aanwezig is, en dit kan tot ongewenst gedrag leiden als u een callback hebt die slechts één keer hoeft te worden uitgevoerd. Hygiënische ontwikkelaars hebben altijd de mogelijkheid gehad om removeEventListener() te gebruiken om dingen expliciet op te ruimen, door patronen te volgen zoals:

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

De equivalente code, die gebruik maakt van de nieuwe parameter once , is overzichtelijker en dwingt je niet om de naam van de gebeurtenis ( event.type , in het vorige voorbeeld) of een verwijzing naar de callback-functie ( cb ) bij te houden. :

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

Het opschonen van uw gebeurtenishandlers kan ook geheugenefficiëntie opleveren door het bereik dat is gekoppeld aan de callback-functie te vernietigen, waardoor alle variabelen die in dat bereik zijn vastgelegd, kunnen worden verzameld. Hier is een voorbeeld waarbij het een verschil zou maken:

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

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

Standaard blijft de callback van de load -gebeurtenislistener binnen het bereik wanneer deze is uitgevoerd, ook al wordt deze nooit meer gebruikt. Omdat de data binnen de callback wordt gebruikt, blijft deze ook binnen het bereik en wordt er nooit afval verzameld. Als de callback echter via de parameter once wordt verwijderd, zullen zowel de functie zelf als alles wat via de reikwijdte ervan in leven wordt gehouden potentieel kandidaten zijn voor garbagecollection.

Browser-ondersteuning

Chrome 55+, Firefox 50+ en Safari's technologievoorbeeld 7+ hebben native ondersteuning voor de once optie.

Veel JavaScript UI-bibliotheken bieden handige methoden voor het maken van gebeurtenislisteners, en sommige hebben snelkoppelingen voor het definiëren van eenmalige gebeurtenissen. De meest opvallende daarvan is jQuery's one() method . Er is ook een polyfill beschikbaar, als onderdeel van dom4 bibliotheek van Andrea Giammarchi .

Bedankt

Met dank aan Ingvar Stepanyan voor feedback over de voorbeeldcode in dit bericht.