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 à
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.