Une fois sur un écouteur d'événements

Petit quiz: à quoi sert le troisième paramètre transmis à addEventListener() ?

Ne soyez pas gêné si vous pensez que addEventListener() n'a pris que deux paramètres, ou peut-être simplement systématiquement coder en dur une valeur de false, avec une compréhension vague du fait que cela a quelque chose à voir avec... les bulles ?

Une fonction addEventListener() plus configurable.

La méthode addEventListener() a beaucoup progressé depuis les débuts du Web, et sa nouvelle fonctionnalité est configurée via une version surboostée de ce troisième paramètre. Les modifications récentes apportées à la définition de la méthode permettent aux développeurs de fournir des options supplémentaires via un objet de configuration, tout en restant rétrocompatible en présence d'un paramètre booléen ou lorsqu'une option n'est pas spécifiée.

Nous avons le plaisir d'annoncer que Chrome 55 prend en charge l'option once dans cet objet de configuration, avec les options passive (implémentées dans Chrome 51) et capture (implémentées dans Chrome 49). Exemple :

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

Vous pouvez combiner ces options selon vos besoins.

Les avantages de faire le ménage sur soi

Voici la syntaxe permettant d'utiliser la nouvelle option once. Qu'est-ce que cela vous donne ? En résumé, il vous offre un écouteur d'événements adapté aux cas d'utilisation ponctuels.

Par défaut, les écouteurs d'événements persistent après leur premier appel, ce que vous souhaitez pour certains types d'événements (des boutons sur lesquels vous pouvez cliquer plusieurs fois, par exemple). Toutefois, pour d'autres utilisations, il n'est pas nécessaire de conserver un écouteur d'événements, ce qui peut entraîner un comportement indésirable si vous avez un rappel qui ne doit s'exécuter qu'une seule fois. Les développeurs spécialisés dans l'hygiène ont toujours eu la possibilité d'utiliser removeEventListener() pour nettoyer explicitement les éléments, en suivant des modèles tels que:

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

Le code équivalent, qui utilise le nouveau paramètre once, est plus propre et ne vous oblige pas à suivre le nom de l'événement (event.type, dans l'exemple précédent) ou une référence à la fonction de rappel (cb):

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

Le nettoyage de vos gestionnaires d'événements peut également améliorer l'efficacité de la mémoire en détruisant le champ d'application associé à la fonction de rappel. Ainsi, toutes les variables capturées dans ce champ d'application peuvent être récupérées de la mémoire. Voici un exemple où cela ferait la différence:

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

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

Par défaut, le rappel de l'écouteur d'événements load reste dans le champ d'application une fois l'exécution terminée, même s'il n'est plus jamais utilisé. Comme la variable data est utilisée dans le rappel, elle restera également dans le champ d'application et ne sera jamais récupérée. Toutefois, si le rappel a été supprimé via le paramètre once, la fonction elle-même et tout ce qui est maintenu actif via son champ d'application seront potentiellement des candidats à la récupération de mémoire.

Prise en charge des navigateurs

Chrome 55+, Firefox 50+ et la version d'aperçu de la technologie 7+ de Safari sont compatibles en natif avec l'option once.

De nombreuses bibliothèques d'UI JavaScript proposent des méthodes pratiques pour créer des écouteurs d'événements. Certaines disposent de raccourcis permettant de définir des événements ponctuels. La plus notable est la méthode one() de jQuery. Un polyfill est également disponible dans la bibliothèque dom4 d'Andrea Giammarchi.

Merci

Merci à Ingvar Stepanyan pour ses commentaires sur l'exemple de code présenté dans cet article.