2017-01-24 2 views
11

J'ai un fortement application JavaScript optimisée, un éditeur graphique hautement interactif. J'ai maintenant commencé à le profiler (en utilisant les dev-tools de Chrome) avec des quantités massives de données (des milliers de formes dans le graphique), et je rencontre un goulot d'étranglement précédemment inhabituel, Hit Test.Optimisation du test de hit natif des éléments DOM (Chrome)

| Self Time  | Total Time  | Activity   | 
|-----------------|-----------------|---------------------| 
| 3579 ms (67.5%) | 3579 ms (67.5%) | Rendering   | 
| 3455 ms (65.2%) | 3455 ms (65.2%) | Hit Test   | <- this one 
| 78 ms (1.5%) | 78 ms (1.5%) | Update Layer Tree | 
| 40 ms (0.8%) | 40 ms (0.8%) | Recalculate Style | 
| 1343 ms (25.3%) | 1343 ms (25.3%) | Scripting   | 
| 378 ms (7.1%) | 378 ms (7.1%) | Painting   | 

Cela prend 65% de tout (!), reste un goulot d'étranglement monstre dans ma base de code. Je sais que c'est le processus de tracer l'objet sous le pointeur, et j'ai mes idées inutiles sur la façon dont cela pourrait être optimisé (utiliser moins d'éléments, utiliser moins d'événements de souris, etc.).

Contexte: Le profil de performance ci-dessus montre une fonction « écran panoramique » dans mon application, où le contenu de l'écran peuvent être déplacés en faisant glisser la zone vide. Il en résulte un grand nombre d'objets déplacés, optimisés en déplaçant leur conteneur au lieu de chaque objet individuellement. I made a demo.


Avant de sauter dans cela, je voulais rechercher les principes généraux d'optimisation des tests de succès (ceux de bonne ol » "Pas sh * t, Sherlock" articles de blog), ainsi comme s'il existait des astuces pour améliorer les performances à cette fin (par exemple en utilisant translate3d pour activer le traitement GPU).

J'ai essayé des requêtes comme js optimize hit test, mais les résultats sont pleins de graphiques et de programmation des articles exemples de mise en œuvre du manuel - il est comme si la communauté JS avait même pas entendu de cette chose avant! Même le chrome devtools guide manque cette zone.

Alors je suis là, fièrement fait mes recherches, demandant: comment puis-je obtenir sur l'optimisation native hit tester en JavaScript?


I prepared a demo qui démontre le goulot d'étranglement de performance, bien que ce n'est pas exactement la même chose que mon application réelle et le nombre variera évidemment par le dispositif aussi bien.Pour voir le goulot d'étranglement:

  1. Allez à l'onglet Timeline sur Chrome (ou l'équivalent de votre navigateur)
  2. Démarrez l'enregistrement, puis un panoramique dans la démo comme un fou-man
  3. Arrêter l'enregistrement et le contrôle les résultats

Un résumé de toutes les optimisations importantes que je l'ai déjà fait dans ce domaine:

  • déplacer un seul conteneur sur l'écran au lieu de déplacer des milliers d'éléments individuellement
  • à l'aide transform: translate3d pour déplacer le récipient
  • mouvement de la souris v-synchronisation à l'écran taux de rafraîchissement
  • éliminer toutes les « wrapper » possible inutile et « fixeur "éléments
  • utilisant pointer-events: none des formes - aucun effet

notes complémentaires:

  • le goulot d'étranglement existe deux avec et sans accélération GPU test
  • n'a été fait dans Chrome, le dernier
  • DOM est rendu à l'aide ReactJS, mais le même problème est observable sans elle, comme vu dans la démo liée
+0

Intéressant, est-ce https://crbug.com/454909 ("Compositor n'honore point-événements: aucun") ou autre chose sous https://bugs.chromium.org/p/chromium/issues/list ? q = composant: Blink% 3EHitTesting? –

+0

@JoshLee Oui, je crois [# 662030] (https://bugs.chromium.org/p/chromium/issues/detail?id=662030) est exactement le même problème que ce que cette question observe. Pour une raison quelconque, mes tentatives de recherche ont raté cette zone. –

Répondre

0

L'un des problèmes est que vous déplacez chaque élément unique à l'intérieur de votre conteneur, peu importe si vous avez une accélération GPU ou non, le goulot de la bouteille est recalcu lating leur nouvelle position, c'est le champ du processeur.

Ma suggestion ici est de segmenter les conteneurs, donc vous pouvez déplacer différentes vitres individuellement, en réduisant la charge, c'est ce qu'on appelle un calcul de phase large, c'est-à-déplacer seulement ce qui doit être déplacé. Si vous avez quelque chose hors de l'écran, pourquoi devriez-vous le déplacer? Commencez par faire au lieu d'un, 16 conteneurs, vous devrez faire quelques calculs ici pour savoir lequel de ces panneaux sont affichés. Ensuite, lorsqu'un événement de souris se produit, déplacez uniquement les volets et laissez ceux qui ne sont pas affichés là où ils se trouvent. Cela devrait réduire considérablement le temps utilisé pour les déplacer.

+------+------+------+------+ 
| SS|SS |  |  | 
| SS|SS |  |  | 
+------+------+------+------+ 
|  |  |  |  | 
|  |  |  |  | 
+------+------+------+------+ 
|  |  |  |  | 
|  |  |  |  | 
+------+------+------+------+ 
|  |  |  |  | 
|  |  |  |  | 
+------+------+------+------+ 

Sur cet exemple, nous avons 16 volets, dont 2 sont montrées (marquées par S pour l'écran). Quand un utilisateur parcourt, cochez la case de délimitation de "l'écran", découvrez quels volets se rapportent à "l'écran", déplacez seulement ces volets. C'est théoriquement infiniment évolutif.

Malheureusement, il me manque le temps d'écrire le code montrant la pensée, mais j'espère que cela vous aide.

À la votre!