Había una vez un objeto de escucha de eventos

Cuestionario emergente: ¿Cuál es el propósito del tercer parámetro que se pasa a addEventListener()?

No debes avergonzarte si pensaste que addEventListener() solo tomaba dos parámetros, o quizás siempre codifica un valor de false, con una comprensión imprecisa de que tiene algo que ver con... ¿burbujas?

Una addEventListener() más configurable

El método addEventListener() ha avanzado mucho desde los primeros días de la Web, y su nueva funcionalidad se configura a través de una versión optimizada de ese tercer parámetro. Los cambios recientes en la definición del método permiten a los desarrolladores proporcionar opciones adicionales a través de un objeto de configuración, sin dejar de ser retrocompatibles cuando hay un parámetro booleano o cuando no se especifica una opción.

Nos complace anunciar que Chrome 55 agrega compatibilidad con la opción once en ese objeto de configuración, junto con las opciones passive (implementadas en Chrome 51) y capture (implementadas en Chrome 49). Por ejemplo:

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

Puedes combinar estas opciones según corresponda a tu propio caso de uso.

Los beneficios de limpiar lo que sucede

Entonces, esa es la sintaxis para usar la nueva opción once, pero ¿en qué consiste? En resumen, te proporciona un objeto de escucha de eventos personalizado para los casos de uso "uno y listo".

De forma predeterminada, los objetos de escucha de eventos persisten después de la primera vez que se los llama, que es lo que deseas para algunos tipos de eventos: botones en los que se puede hacer clic varias veces. Sin embargo, para otros usos, no es necesario que un objeto de escucha de eventos se mantenga y puede generar un comportamiento no deseado si tienes una devolución de llamada que solo debe ejecutarse una vez. Los desarrolladores de mantenimiento siempre tuvieron la opción de usar removeEventListener() para realizar una limpieza de forma explícita y seguir patrones como los siguientes:

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

El código equivalente, que usa el nuevo parámetro once, es más claro y no te obliga a hacer un seguimiento del nombre del evento (event.type, en el ejemplo anterior) ni una referencia a la función de devolución de llamada (cb):

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

La limpieza de los controladores de eventos también puede mejorar la eficiencia de la memoria, ya que destruye el alcance asociado con la función de devolución de llamada, lo que permite que se recolecten las variables capturadas en ese alcance como elementos no utilizados. A continuación, se muestra un ejemplo en el que marcaría una diferencia:

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

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

De forma predeterminada, la devolución de llamada del objeto de escucha de eventos load permanecerá dentro del alcance cuando termine de ejecutarse, incluso si nunca se vuelve a usar. Debido a que la variable data se usa dentro de la devolución de llamada, también permanecerá dentro del alcance y nunca se recolectarán elementos no utilizados. Sin embargo, si se quitó la devolución de llamada a través del parámetro once, la función en sí y todo lo que se haya mantenido activa a través de su alcance posiblemente sean candidatos para la recolección de elementos no utilizados.

Navegadores compatibles

Chrome 55 y versiones posteriores, Firefox 50 y versiones posteriores, y la vista previa de tecnología 7 y versiones posteriores de Safari tienen compatibilidad nativa para la opción once.

Muchas bibliotecas de la IU de JavaScript proporcionan métodos convenientes para crear objetos de escucha de eventos, y algunas tienen atajos para definir eventos únicos. El más destacado es el método one() de jQuery. También hay un polyfill disponible como parte de la biblioteca dom4 de Andrea Giammarchi.

Gracias

Agradecemos a Ingvar Stepanyan por sus comentarios sobre el código de muestra de esta publicación.