De onde isso vem
Quando aprendi o jQuery, normalmente anexava eventos como este:
$('.my-widget a').click(function() {
$(this).toggleClass('active');
});
Depois de aprender mais sobre a velocidade do seletor e a delegação de eventos, li em vários lugares que "a delegação de eventos do jQuery tornará seu código mais rápido". Então comecei a escrever código como este:
$('.my-widget').on('click','a',function() {
$(this).toggleClass('active');
});
Essa também foi a maneira recomendada de replicar o comportamento do evento .live () descontinuado. O que é importante para mim, pois muitos dos meus sites adicionam / removem dinamicamente widgets o tempo todo. Porém, o acima não se comporta exatamente como .live (), pois apenas os elementos adicionados ao contêiner já existente '.my-widget' receberão o comportamento. Se eu adicionar dinamicamente outro bloco de html após a execução desse código, esses elementos não vincularão os eventos a eles. Como isso:
setTimeout(function() {
$('body').append('<div class="my-widget"><a>Click does nothing</a></div>');
}, 1000);
O que eu quero alcançar:
- o antigo comportamento de .live () // significa anexar eventos a elementos ainda não existentes
- os benefícios de .on ()
- desempenho mais rápido para vincular eventos
- Maneira simples de gerenciar eventos
Agora, anexo todos os eventos como este:
$(document).on('click.my-widget-namespace', '.my-widget a', function() {
$(this).toggleClass('active');
});
O que parece cumprir todos os meus objetivos. (Sim, é mais lento no IE por algum motivo, não faz ideia do porquê?) É rápido porque apenas um único evento está vinculado a um elemento singular e o seletor secundário é avaliado apenas quando o evento ocorre (me corrija se isso estiver errado aqui). O espaço para nome é incrível, pois facilita a alternância do ouvinte de evento.
Minha Solução / Pergunta
Então, estou começando a pensar que os eventos do jQuery devem sempre estar vinculados a $ (documento).
Existe alguma razão para você não querer fazer isso?
Isso poderia ser considerado uma prática recomendada? Se não, por que?
Se você leu tudo isso, obrigado. Agradeço qualquer / todos os comentários / idéias.
Premissas:
- Usando jQuery que suporta
.on()
// pelo menos a versão 1.7 - Você deseja que o evento seja adicionado ao conteúdo adicionado dinamicamente
Leituras / Exemplos:
Respostas:
Não - você NÃO deve vincular todos os manipuladores de eventos delegados ao
document
objeto. Esse é provavelmente o cenário com pior desempenho que você pode criar.Primeiro, a delegação de eventos nem sempre torna seu código mais rápido. Em alguns casos, é vantajoso e, em alguns casos, não. Você deve usar a delegação de eventos quando realmente precisar da delegação de eventos e quando se beneficiar dela. Caso contrário, você deve vincular manipuladores de eventos diretamente aos objetos em que o evento acontece, pois isso geralmente será mais eficiente.
Segundo, você NÃO deve vincular todos os eventos delegados no nível do documento. É exatamente por isso que
.live()
foi preterido, porque isso é muito ineficiente quando você tem muitos eventos vinculados dessa maneira. Para manipulação de eventos delegados, é MUITO mais eficiente vinculá-los ao pai mais próximo que não é dinâmico.Terceiro, nem todos os eventos funcionam ou todos os problemas podem ser resolvidos com a delegação. Por exemplo, se você deseja interceptar eventos-chave em um controle de entrada e impedir que chaves inválidas sejam inseridas no controle de entrada, não é possível fazer isso com a manipulação de eventos delegados porque, quando o evento chegar ao manipulador delegado, ele já estará foi processado pelo controle de entrada e é tarde demais para influenciar esse comportamento.
Aqui estão os momentos em que a delegação de eventos é necessária ou vantajosa:
Para entender um pouco mais, é preciso entender como os manipuladores de eventos delegados do jQuery funcionam. Quando você chama algo assim:
Ele instala um manipulador de eventos jQuery genérico no
#myParent
objeto. Quando um evento de clique é associado a esse manipulador de eventos delegados, o jQuery precisa percorrer a lista de manipuladores de eventos delegados anexados a esse objeto e verificar se o elemento de origem do evento corresponde a algum dos seletores nos manipuladores de eventos delegados.Como os seletores podem ser bastante envolvidos, isso significa que o jQuery precisa analisar cada seletor e compará-lo às características do destino do evento original para ver se ele corresponde a cada seletor. Esta não é uma operação barata. Não é grande coisa se houver apenas um deles, mas se você colocar todos os seus seletores no objeto de documento e houver centenas de seletores para comparar com cada evento com bolhas, isso poderá prejudicar seriamente o desempenho da manipulação de eventos.
Por esse motivo, você deseja configurar seus manipuladores de eventos delegados para que um manipulador de eventos delegados fique o mais próximo possível do objeto de destino. Isso significa que menos eventos serão exibidos em cada manipulador de eventos delegados, melhorando assim o desempenho. Colocar todos os eventos delegados no objeto de documento é o pior desempenho possível, porque todos os eventos com bolhas precisam passar por todos os manipuladores de eventos delegados e serem avaliados com relação a todos os possíveis seletores de eventos delegados. É exatamente por isso que
.live()
foi preterido, porque foi o que.live()
aconteceu e provou ser muito ineficiente.Portanto, para alcançar um desempenho otimizado:
fonte
$(document).on('click', '[myCustomAttr]', function () { ... });
?document
, ou vincular a seleções mais específicaspage:load
e desvincular esses eventospage:after-remove
? HmmmA delegação de eventos é uma técnica para gravar seus manipuladores antes que o elemento realmente exista no DOM. Este método tem suas próprias desvantagens e deve ser usado apenas se você tiver esses requisitos.
Quando você deve usar a delegação de eventos?
Por que você não deve usar a delegação de eventos?
PS: Mesmo para conteúdos dinâmicos, você não precisa usar o método de delegação de eventos se for vincular o manipulador após a inserção do conteúdo no DOM. (Se o conteúdo dinâmico for adicionado com frequência, não será removido / adicionado novamente)
fonte
Aparentemente, a delegação de eventos é realmente recomendada agora. pelo menos para baunilha js.
https://gomakethings.com/why-event-delegation-is-a-better-way-to-listen-for-events-in-vanilla-js/
"Desempenho na Web # Parece que ouvir cada clique no documento seria ruim para o desempenho, mas na verdade é mais eficiente do que ter vários ouvintes de eventos em itens individuais".
fonte
Gostaria de acrescentar algumas observações e contra-argumentos à resposta de jfriend00. (principalmente apenas minhas opiniões baseadas no meu instinto)
Embora seja verdade que o desempenho possa ser um pouco melhor se você apenas se registrar e realizar um evento para um único elemento, acredito que ele não compensa os benefícios de escalabilidade que a delegação traz. Também acredito que os navegadores estão lidando com isso de maneira cada vez mais eficiente, embora não tenha provas disso. Na minha opinião, a delegação de eventos é o caminho a seguir!
Eu meio que concordo com isso. Se você tem 100% de certeza de que um evento ocorrerá apenas dentro de um contêiner, faz sentido vincular o evento a esse contêiner, mas eu ainda argumentaria contra a vinculação de eventos diretamente ao elemento acionador.
Isto simplesmente não é verdade. Por favor, veja este códigoPen: https://codepen.io/pwkip/pen/jObGmjq
Ele ilustra como você pode impedir que um usuário digite digitando o evento de pressionamento de tecla no documento.
Gostaria de responder com esta citação de https://ehsangazar.com/optimizing-javascript-event-listeners-for-performance-e28406ad406c
Event delegation promotes binding as few DOM event handlers as possible, since each event handler requires memory. For example, let’s say that we have an HTML unordered list we want to bind event handlers to. Instead of binding a click event handler for each list item (which may be hundreds for all we know), we bind one click handler to the parent unordered list itself.
Além disso, pesquisar no Google
performance cost of event delegation google
retorna mais resultados em favor da delegação de eventos.Onde isso está documentado? Se isso for verdade, o jQuery parece estar lidando com a delegação de uma maneira muito ineficiente, e meus contra-argumentos devem ser aplicados apenas ao JS vanilla.
Ainda assim: eu gostaria de encontrar uma fonte oficial que apoie essa reivindicação.
:: EDIT ::
Parece que o jQuery está realmente fazendo bolhas de eventos de uma maneira muito ineficiente (porque eles suportam o IE8) https://api.jquery.com/on/#event-performance
Portanto, a maioria dos meus argumentos aqui é válida apenas para JS vanilla e navegadores modernos.
fonte