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ê pensou que addEventListener() precisava de apenas dois parâmetros ou talvez sempre codificar um valor de false, com uma vaga compreensão de que isso tem algo a ver com… bolhas?

Um addEventListener() mais configurável

O método addEventListener() percorreu um longo caminho desde os primeiros dias da Web, e a nova funcionalidade dele é configurada por uma versão superpotência desse terceiro parâmetro. Mudanças recentes na definição do método permitem que os desenvolvedores ofereçam opções adicionais usando um objeto de configuração, mantendo a compatibilidade 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 (implementada no Chrome 51) e capture (implementada no Chrome 49). Exemplo:

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

Você pode combinar essas opções de acordo com seu caso de uso.

Os benefícios de limpar depois de si mesmo

Essa é a sintaxe para usar a nova opção once, mas o que ela faz? Em resumo, ele fornece um listener de eventos personalizado para casos de uso "pronto para uso".

Por padrão, os listeners de eventos persistem após a primeira vez que são chamados, o que é o que você quer para alguns tipos de eventos, como botões que podem ser clicados várias vezes, por exemplo. Para outros usos, no entanto, não é necessário manter um listener de eventos e isso pode levar a um comportamento indesejado se você tiver um callback que só precisa ser executado uma vez. Os desenvolvedores higiênicos sempre tiveram a opção de usar removeEventListener() para limpar as coisas 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});

A limpeza dos manipuladores de eventos também pode oferecer eficiência de memória, destruindo o escopo associado à função de callback, permitindo que todas as variáveis capturadas nesse escopo sejam coletadas. 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 vai permanecer no escopo quando terminar a execução, mesmo que nunca seja usado novamente. Como a variável data é usada no callback, ela também permanece no escopo e nunca recebe a coleta de lixo. No entanto, se o callback for removido pelo parâmetro once, a própria função e tudo o que for mantido vivo pelo escopo dela poderá ser candidato à coleta de lixo.

Suporte ao navegador

O Chrome 55 e versões mais recentes, o Firefox 50 e versões mais recentes e a pré-visualização de tecnologia 7 e versões 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 conhecido é o método one() do jQuery. Um polyfill também está disponível como parte da biblioteca dom4 do Andrea Giammarchi.

Obrigado

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