Desempenho e eventos jQuery: event delegation

Todo mundo que leva a experiência de uso da sua página um pouco a sério já se pegou pensando “uso um plugin pronto ou faço eu mesmo?” e caso cogite usar algo já pronto, acaba em dúvida sobre quais das várias opções usar. Esses dias eu resolvi estudar o código de algumas opções disponíveis. Fiquei

Todo mundo que leva a experiência de uso da sua página um pouco a sério já se pegou pensando “uso um plugin pronto ou faço eu mesmo?” e caso cogite usar algo já pronto, acaba em dúvida sobre quais das várias opções usar.

Esses dias eu resolvi estudar o código de algumas opções disponíveis. Fiquei com medo.

Existem algumas falhas que nós desenvolvedores cometemos no desenvolvimento usando jQuery que são críticas e comuns. Hoje eu quero falar sobre uma delas em especial:

Excesso de event listeners pela página

Acho que todo mundo já escreveu um código similar a este:

Você sabe o que esse código faz? Ele coloca em todos os elementos com a classe foo da sua página um event listener que dispara um callback handler sempre que o usuário clicar nele. No caso esse listener dispara a função callback. Legal e útil, né?

Agora imagine que você tenha 100 elementos com a classe foo. Serão 100 event listeners para o navegador tomar conta. Imagine que você coloque outros listeners para outros eventos e seletores. Dá pra perceber que essa conta não escala muito bem, né?

A melhor maneira de resolver isso é com event delegation.

Vamos supor que nossa class foo seja aplicada à

de um tipo de tabela específica. Algo assim:

Se a gente colocar um listener diretamente na class da tabela (.tar) mandando ele ouvir os eventos internos que ocorrerem nos elementos (.foo), vamos reduzir o número de listeners espalhados pela página.

Como se faz isso, Léo?

Assim:

Essa linha de código basicamente diz: sempre que houver um evento de clique nos elementos com classe tar selecionados, verifique se esse evento foi disparado por um elemento interno com a classe foo. Se sim, execute a função callback.

Isso pode ser feito pois os eventos do DOM normalmente são transmitidos (ou propagam) (ou propagam) à todos os seus elementos pais na árvore DOM. Esse é o caso do evento de clique.

Logo, o exemplo acima teria quase o mesmo efeito caso fosse escrito desse jeito:

Você pode adicionar um event listener para responder a cliques no documento inteiro e só executar o callback caso o clique tenha ocorrido em elementos especificados, nesse caso ‘.foo’.

Lembra que a gente está falando de melhora de desempenho? Se você forçar o navegador a ouvir todos os cliques na sua página e só executar em casos específicos, você estará disperdiçando recursos. Não faça isso, a não ser que seja extremamente necessário. Busque sempre  fixar seus eventos em elementos wrappers, como aquele do exemplo.

Elementos adicionados dinâmicamente

Usar event delegation ainda garante um bônus: ter event handlers disparados por elementos que foram adicionados dinamicamente à página.

Digamos que o listener seja criado durante o document ready, como tradicionalmente é feito:

O handler será anexado somente aos elementos com a classe foo existentes no momento em que o documento for carregado.

Se posteriormente você criar novos elementos com a classe foo (como respostas à ações do usuário, AJAX, etc.), eles não vão ter o event listener e não ocorrerá o efeito desejado quando o usuário clica-los.

Se nós delegarmos isso para um elemento pai das , como no caso o , não teremos esse problema.

É possível inspecionar o documento através do DevTools do seu navegador e identificar quais event listeners estão anexados em cada elemento. Essa pode ser uma boa estratégia inicial para auditar a sua página e verificar quais eventos podem ser anexados em elementos mais específicos, além de eliminar possíveis excessos no document.

Conclusão

Cada event listener que criamos é incluído na memória utilizada pelo navegador, o excesso deles pode causar um uso excessivo de memória e deixar a sua página bem pesada. Assim como não é recomendável observar os eventos em muitos elementos, não é para fixar tudo em um único elemento pai, como o próprio document, pois você corre o risco de ter muitos listeners sendo disparados ao mesmo tempo atoa, o que pode deixar as interações de sua página bem lentas.

Nem muito específico, nem muito genérico. O importante é observar que a utilização de event delegation com o jQuery pode ser otimizada e que se deve tomar cuidado para não trocar uma má prática por outra.

No próximo artigo vou falar sobre como evitar colisão e duplicação de eventos.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *