Uma vez que um listener de eventos

Teste rápido: qual é a finalidade do terceiro parâmetro transmitido para addEventListener()?

Não se sinta envergonhado se você achou que addEventListener() só tomou dois parâmetros, ou talvez apenas fixou no código um valor de false, entendendo vago que tem algo a ver com... bolhas?

Um addEventListener() mais configurável

O método addEventListener() evoluiu muito desde os primórdios da Web, e a nova funcionalidade é configurada por uma versão sobrecarregada desse terceiro parâmetro. Mudanças recentes na definição do método permitem que os desenvolvedores ofereçam outras opções usando um objeto de configuração, permanecendo compatíveis com versões anteriores quando há um parâmetro booleano ou quando uma opção não é especificada.

Temos o prazer de anunciar que o Chrome 55 adiciona suporte à opção once nesse objeto de configuração, junto com as opções passive (implementadas no Chrome 51) e capture (implementadas no Chrome 49). Exemplo:

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

É possível misturar e combinar essas opções conforme apropriado com seu caso de uso.

Os benefícios de fazer a limpeza depois de si

Essa é a sintaxe para usar a nova opção once, mas o que isso significa? Em resumo, ele oferece um listener de eventos personalizado para os casos de uso "um e concluído".

Por padrão, os listeners de eventos persistem após a primeira vez que são chamados, que é o que você quer para alguns tipos de eventos, como botões que podem ser clicados várias vezes, por exemplo. No entanto, para outros usos, não é necessário manter um listener de eventos e pode levar a um comportamento indesejável se você tiver um callback que precisa ser executado apenas uma vez. Os desenvolvedores íntegros sempre tiveram a opção de usar removeEventListener() para fazer a limpeza explicitamente, seguindo padrões como:

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

O código equivalente, que usa o novo parâmetro once, é mais limpo e não força você a acompanhar o nome do evento (event.type, no exemplo anterior) ou uma referência à função de callback (cb):

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

Limpar os manipuladores de eventos também pode aumentar a eficiência da memória, destruindo o escopo associado à função de callback, permitindo que todas as variáveis capturadas nesse escopo sejam coletadas como lixo. Confira um exemplo em que isso faria diferença:

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

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

Por padrão, o callback do listener de eventos load permanecerá no escopo quando terminar a execução, mesmo que nunca seja usado novamente. Como a variável data é usada dentro do callback, ela também permanecerá no escopo e nunca será coletada de lixo. No entanto, se o callback for removido pelo parâmetro once, a função em si e qualquer item que seja mantido ativo pelo escopo poderão se tornar candidatos à coleta de lixo.

Suporte ao navegador

O Chrome 55, o Firefox 50 e a prévia de tecnologia 7 e mais recentes do Safari têm suporte nativo para a opção once.

Muitas bibliotecas de interface JavaScript oferecem métodos convenientes para criar listeners de eventos, e algumas têm atalhos para definir eventos únicos. O mais notável é o método one() do jQuery. Um polyfill também está disponível como parte da biblioteca dom4 de Andrea Giammarchi (links em inglês).

Até logo!

Agradecemos a Ingvar Stepanyan pelo feedback sobre o código de exemplo desta postagem.