jQuery mousemove performance – événements d’accélération?

Nous sums confrontés à un problème de performances de propagation d’événement jQuery connecté à mousemove:

Nous avons un canevas de remplissage d’écran et devons savoir si un utilisateur y fait glisser la souris. Nous avons donc ajouté un écouteur de déplacement de la souris sur cet object, comme ceci:

ourCanvas.on('mousemove', function(event) { event.preventDefault(); //our drag code here } }); 

Ce code fonctionne bien, mais nous avons eu de graves problèmes de performances dans l’actuel Firefox (24) sur un système de test. Le profileur nous dit que la plupart du temps a été passé dans jQuery.event.dispatch() (nous avons essayé les dernières versions de jQuery 1.8, 1.9, 1.10 et 2.0).

Nous avons réussi à réduire le temps passé dans la fonction dispatch () en utilisant l’optimisation des performances “jQuery.event.fix ()” ici: http://bitovi.com/blog/2012/04/faster-jquery-event-fix. html, mais les performances de ce système de test étaient encore bien inférieures à nos attentes.

Après quelques tests supplémentaires, j’ai réussi à épingler ceci sur la souris utilisée sur le système: Elle utilisait 1000Hz . Nous avons réglé la souris utilisée à 125Hz et le tour est joué, la performance était excellente.

Notre hypothèse était que le taux de Hz élevé sur la souris causait de nombreux événements mousemove. Nous avons donc modifié le code ci-dessus pour appliquer une régulation d’événement et n’appeler que le traitement de l’événement toutes les X millisecondes:

 var lastMove = 0; var eventThrottle = 1; ourCanvas.on('mousemove', function(event) { event.preventDefault(); var now = Date.now(); if (now > lastMove + eventThrottle) { lastMove = now; //our drag code here } } }); 

Et cela a fonctionné comme un charme, la performance était excellente. Même si nous ne sautons que deux millisecondes d’événements.

Maintenant, j’ai deux questions:

  1. Nous avons d’autres emplacements où nous attachons des écouteurs mousemove à différents éléments HTML et je voudrais append cette manette fabriquée à la main à tous ces gestionnaires de mousemove pour ne plus avoir à faire face au problème. Est-ce que cela est possible d’une manière intéressante dans jQuery (2.0.3)? J’ai vu des preDispatch dans le javascript jQuery, mais ils se trouvent déjà après l’appel à fix (), qui utilise également un certain temps, et j’aimerais également enregistrer cet appel.

  2. Le fait qu’un eventThrottle de 2 ms eventThrottle permette déjà d’obtenir de très bonnes performances me eventThrottle J’ajoute un compteur pour voir le nombre d’événements ignorés. Le résultat surprenant: il ne saute que les événements 0-1 … Avec un accélérateur de 100 ms, les événements ignorés étaient de l’ordre de 60 à 70. Par conséquent, s’il ya moins d’un événement mousemove par ms, pourquoi ce code a-t-il une telle un effet positif après tout?

Merci pour tout commentaire, Christopher

À la fin de 2015, j’ai découvert ce que j’avais découvert en fin de compte.

Dans mon application de navigateur, je peins plusieurs cercles de différentes tailles à des emplacements particuliers, puis je déplace la partie visible de l’écran total pour ne révéler que les cercles de l’arrière-plan visibles au niveau de zoom actuel. Le fait de faire glisser la souris génère un événement mousemove, qui déclenche un appel à ma routine de rendu, ce qui entraîne à son tour une nouvelle peinture pour chaque cercle visible.

En testant cela dans IE 11, j’ai constaté qu’une fois que j’avais plus de 100 cercles dans la zone visible, le rendu tout en faisant glisser la souris devenait extrêmement saccadé. Le profileur a indiqué que cela était presque entièrement dû à la routine paint ().

Mon code utilisait déjà requestAnimationFrame () à partir d’une bibliothèque. Fait intéressant, en faisant glisser l’écran, j’ai vu le ralentissement; mais si je ne faisais que glisser l’écran et le relâcher, laissant le code de la bibliothèque continuer à animer le mouvement avec décélération, la peinture était lisse comme du beurre. Le ralentissement s’est produit uniquement en faisant glisser la souris. Le problème semblait définitivement être avec mousemove. (Retour à cela dans un instant.)

J’ai réduit la routine paint () à un simple arc rempli – le même problème. J’ai essayé de peindre le cercle rempli sur un canevas hors écran à chaque fois que je changeais le niveau de zoom, puis d’utiliser drawImage () pour copier le canevas hors écran sur mon écran principal. Cette performance améliorée, mais restait inutilement agitée dans IE. J’ai ensuite essayé d’utiliser cette technique pour peindre tous les cercles sur un canevas hors écran de la même taille que ma fenêtre visible principale, puis changer de peinture () pour ne faire que copier le canevas hors-plan sur mon canevas visible, ce qui a encore donné une légère amélioration. mais pas assez.

J’ai ensuite essayé d’exécuter mon application dans différents navigateurs:

IE 11: très agité Firefox 42: très agité Chrome 47: parfaitement lisse à tous les niveaux de zoom Opera 34: parfaitement lisse à tous les niveaux de zoom Desktop Safari 5.1.7 (sur PC): légèrement agité à tous les niveaux de zoom

Le problème était définitivement lié au déplacement de souris et à la façon dont il est géré par différents navigateurs.

Finalement, j’ai trouvé cette question sur StackOverflow et sa suggestion selon laquelle la souris elle-même envoie tellement d’événements mousemove qu’elle empêche le navigateur de repeindre assez rapidement. Et j’ai une souris moderne avec un taux de génération d’événements élevé.

J’ai essayé d’append le contrôle eventThrottle à mon gestionnaire d’événements mousemove, et le tour est joué! Succès. Mon code s’affiche maintenant correctement sur tous les navigateurs. (Vote positif avec plaisir. :))

Je voulais append ces informations supplémentaires à toute personne susceptible de rencontrer le problème de mauvaises performances de paint () dans IE et Firefox lors du glisser-déplacer avec une souris haute fréquence. La solution proposée pour étrangler les événements de souris a fonctionné pour moi.

1 – il existe un plugin d’accélération jQuery: https://github.com/cowboy/jquery-throttle-debounce

Comme vous pouvez le lire dans les exemples , vous pouvez remplacer:

 // Bind the not-at-all throttled handler to the resize event. $(window).resize( handler ); // Bind the throttled handler to the resize event. $(window).resize( $.throttle( 250, handler ) ); // This is the line you want! 

2 – voulez-vous publier le code de votre gestionnaire?

Une suggestion à l’aveugle: Firebug a des problèmes de performances avec FF 24. Avez-vous essayé de comparer les performances avec Firebug activé / désactivé?