Un listener di eventi

Domanda al volo: qual è lo scopo del terzo parametro passato a addEventListener()?

Non sentirti in imbarazzo se pensavi che addEventListener() accettasse solo due parametri o se magari hai sempre hardcoded un valore di false, con la vaga consapevolezza che ha qualcosa a che fare con le bolle.

Un addEventListener() più configurabile

Il metodo addEventListener() ha fatto molta strada dai primi giorni del web e la sua nuova funzionalità viene configurata tramite una versione potenziata del terzo parametro. Le modifiche recenti alla definizione del metodo consentono agli sviluppatori di fornire opzioni aggiuntive tramite un oggetto di configurazione, mantenendo la compatibilità con le versioni precedenti quando è presente un parametro booleano o quando non è specificata un'opzione.

Siamo lieti di annunciare che Chrome 55 aggiunge il supporto per l'opzione once in questo oggetto di configurazione, insieme alle opzioni passive (implementata in Chrome 51) e capture (implementata in Chrome 49). Ad esempio:

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

Puoi combinare queste opzioni in base al tuo caso d'uso.

Vantaggi della pulizia dopo l'uso

Questa è la sintassi per utilizzare la nuova opzione once, ma cosa ti offre? In breve, ti offre un listener di eventi personalizzato per i casi d'uso "una tantum".

Per impostazione predefinita, gli ascoltatori di eventi rimangono attivi dopo la prima chiamata, il che è ciò che vuoi per alcuni tipi di eventi, ad esempio i pulsanti su cui è possibile fare clic più volte. Per altri utilizzi, però, non è necessario mantenere attivo un listener di eventi e questo può comportare un comportamento indesiderato se hai un callback che deve essere eseguito una sola volta. Gli sviluppatori che si attengono alle best practice di igiene del codice hanno sempre avuto la possibilità di utilizzare removeEventListener() per ripulire esplicitamente il codice, seguendo pattern come:

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

Il codice equivalente, che utilizza il nuovo parametro once, è più pulito e non ti obbliga a tenere traccia del nome dell'evento (event.type nell'esempio precedente) o di un riferimento alla funzione di callback (cb):

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

La pulizia dei gestori eventi può anche offrire efficienze in termini di memoria distruggendo l'ambito associato alla funzione di callback, consentendo a qualsiasi variabile acquisita in quell'ambito di essere sottoposta a garbage collection. Ecco un esempio in cui può fare la differenza:

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

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

Per impostazione predefinita, il callback dell'ascoltatore di eventi load rimarrà nell'ambito al termine dell'esecuzione, anche se non viene mai più utilizzato. Poiché la variabile data viene utilizzata all'interno del callback, rimarrà anche nell'ambito e non verrà mai raccolta come spazzatura. Tuttavia, se il callback viene rimosso tramite il parametro once, sia la funzione stessa sia tutto ciò che viene mantenuto attivo tramite il relativo ambito saranno potenzialmente candidati per la raccolta dei rifiuti.

Supporto browser

Chrome 55 e versioni successive, Firefox 50 e versioni successive e la anteprima della tecnologia 7 e versioni successive di Safari hanno il supporto nativo per l'opzione once.

Molte librerie UI JavaScript forniscono metodi di utilità per la creazione di ascoltatori di eventi e alcune hanno scorciatoie per definire eventi una tantum, tra cui il metodo one() di jQuery. È disponibile anche un polyfill, nell'ambito della libreria dom4 di Andrea Giammarchi.

Grazie

Grazie a Ingvar Stepanyan per il feedback sul codice di esempio in questo post.