Le moyen le plus efficace de lier dynamicment les gestionnaires d’événements

Problème: Je dois lier un nombre quelconque de gestionnaires d’événements à un nombre quelconque d’éléments (nœuds DOM, window , document ) lors de l’exécution dynamic et pouvoir mettre à jour la liaison des événements pour les nœuds créés (ou détruits) de manière dynamic pendant la durée de vie de mon page. Je peux voir trois options pour résoudre ce problème:

I) Délégation d’événement sur la window
II) Liaison d’événement directe sur chaque nœud
III) Délégation d’événements sur des ancêtres communs (qui serait inconnue jusqu’à l’exécution et devrait éventuellement être recalculée lorsque le DOM est modifié)

Quel est le moyen le plus efficace de le faire?

Un peu de contexte

Je travaille sur un ensemble de pages qui nécessitent un suivi analytique pour les événements utilisateur (clics, défilement, etc.) et je veux pouvoir configurer facilement ces gestionnaires d’événements sur un tas de pages sans avoir besoin d’écrire un script pour gérer l’événement. obligatoire pour chaque instance. De plus, étant donné que je pourrais avoir besoin de suivre de nouveaux événements dans le futur, ou de suivre des événements d’éléments ajoutés dynamicment à la page / supprimés de celle-ci, je dois pouvoir prendre en compte les modifications apscopes au DOM pendant la durée de vie. de la page.

Par exemple, j’aimerais créer une fonction qui accepte un object config qui permet au programmeur de spécifier des gestionnaires par défaut pour chaque événement et de les remplacer par des éléments spécifiques:

 Analytics.init({ // default handlers for each event type defaultHandlers: { "click": function(e) { ... }, "focus": function(e) { ... } }, // elements to listen to targetElements: { // it should work with non-DOM nodes like 'window' and 'document' window: { // events for which the default handlers should be called useDefaultHandlers: ['click'], // custom handler "scroll": function(e) { ... } }, // it should work with CSS selectors "#someId": { useDefaultHandlers: ['click', 'focus'], "blur": function(e) { ... } } } }); 

Sources

  • SO: Tous les événements jQuery doivent-ils être liés à la documentation?
  • SO: Comment trouver les ancêtres communs les plus proches de deux nœuds ou plus
  • Documents jQuery: $ .fn.on ()

Je délègue généralement des événements sur l’object document.documentElement raisons suivantes:

  1. Il représente l’élément de la page, qui contient tout ce qui contient toutes les balises HTML avec lesquelles l’utilisateur peut interagir.
  2. Il est disponible au moment où JavaScript commence à s’exécuter, éliminant ainsi le besoin de charger une fenêtre ou de gérer un événement prêt pour le DOM.
  3. Vous pouvez toujours capturer des événements de “défilement”

En ce qui concerne l’efficacité de la délégation d’événements, plus il faut de noeuds, plus il faut de noeuds, mais nous parlons d’environ 1 à 2 ms de différence de temps – peutêtre . C’est imperceptible pour l’utilisateur. C’est généralement le traitement d’un événement DOM qui introduit une pénalité de performance, et non le bouillonnement de l’événement d’un nœud à un autre.

J’ai constaté que les problèmes suivants affectaient négativement les performances de JavaScript en général:

  1. Plus le nombre de nœuds dans l’arborescence de documents est important, plus le navigateur prend du temps pour le manipuler.
  2. Plus le nombre de gestionnaires d’événements sur la page est élevé, plus JavaScript ralentit, même si vous avez besoin de centaines de gestionnaires pour voir la différence.

Principalement, le n ° 1 a le plus grand impact. Je pense qu’essayer d’améliorer les performances dans la gestion des événements est une optimisation prématurée dans la plupart des cas. Le seul cas que je vois pour optimiser le code de gestion des événements concerne les événements qui se déclenchent plusieurs fois par seconde (par exemple, les événements “scroll” et “mousemove”). L’avantage supplémentaire de la délégation d’événements est que vous n’avez pas à nettoyer les gestionnaires d’événements sur les nœuds DOM qui seront détachés de l’arborescence de documents, ce qui permet au navigateur de récupérer la mémoire.

(D’après les commentaires ci-dessous) wvandell a déclaré:

Les coûts de performance liés à la délégation d’événements ont peu à voir avec le «bouillonnement» réel des événements. La délégation de nombreux sélecteurs à un seul parent entraîne un risque de perte de performances.

Cela est vrai, cependant, pensons à la performance perçue . La délégation de nombreux événements de clic ne sera pas perceptible par l’utilisateur. Si vous mousemove un événement tel que scroll ou mousemove , pouvant se déclencher plus de 50 fois par seconde (20 ms pour le traitement de l’événement), l’utilisateur peut percevoir un problème de performances. Cela revient à mon argument contre l’optimisation prématurée du code du gestionnaire d’événements.

De nombreux événements de clic peuvent être delegates sans problème sur un ancêtre commun, tel que document.documentElement . Est-ce que je pourrais déléguer un événement “mousemove”? Peut être. Cela dépend de ce qui se passe et si cet événement de “déplacement de souris” délégué est suffisamment réactif.