HeadlinesBriefing favicon HeadlinesBriefing.com

Performance Thread Principal Navigateur

Hacker News •
×

Qu'est-ce qui vous vient à l'esprit quand vous entendez "optimisation frontend" ? Pour la plupart d'entre nous, ce sont des choses comme réduire les requêtes réseau, réduire la taille du bundle, ou faire bon usage du cache. Au-delà de cela, peut-être réduire les re-rendus ou ajuster le moment où les ressources sont chargées. Le thread principal ne vient généralement pas à l'ordre du jour, et il y a une raison à cela : sur la plupart des écrans, il ne devient jamais un problème.

Mais sur les écrans avec beaucoup d'interaction, où les données arrivent en direct et le défilement, l'animation et l'entrée s'entremêlent, la donne change. Combien que vous économisiez sur le réseau et la taille du bundle, l'écran gèle au moment où le thread principal est bloqué. Vous avez probablement rencontré un site web où le défilement bégaye de temps en temps, un bouton répond avec un léger retard, ou les lettres que vous tapez dans une boîte de recherche apparaissent avec un demi-temps de retard.

Ce n'est pas assez grave pour être agaçant, mais cela vous agace subtilement. Ce genre de "jank" est ce à quoi ressemble un thread principal bloqué. Lorsque nous rencontrons du jank comme celui-ci en tant que développeurs, la réaction habituelle est de se demander "mon code est-il lent ?" et de commencer à disséquer les algorithmes ou à chercher des calculs gaspillés.

Dans la plupart des cas, cependant, la vitesse du code n'est pas le problème. Le code n'est pas lent. Il se trouve juste être le code qui tient le thread principal.

Le navigateur a plusieurs threads, mais presque tout ce que nous pouvons toucher depuis le code est concentré sur le thread principal. Calcul, rendu, gestion des événements, gestion de la réponse réseau, et les internes de votre framework sont tous traités là. Une ressource, une montagne de travail.

Le thread principal du navigateur est coûteux. La plupart du temps, il ne cause pas de problèmes, mais une fois que vous essayez de faire quelque chose d'ambitieux, gérer le thread principal devient la partie importante. Cet article traite de la façon de gérer cette ressource coûteuse.

Commençons par ce que le thread principal fait réellement. Son travail se divise en deux grandes catégories. La première est l'exécution de JavaScript.

Le code que nous écrivons, avec les gestionnaires d'événements, les minuteurs, les callbacks de réponse réseau, et les internes du framework, tout s'exécute ici. Ces tâches s'exécutent dans l'ordre où elles entrent dans la file d'attente, chaque fois qu'il y a un créneau, sans relation avec le cycle de rafraîchissement de l'écran. La seconde est le dessin de l'écran.

Lorsque le DOM ou les styles changent et que l'écran a besoin d'être mis à jour, le navigateur passe par approximativement ces étapes, dans l'ordre, pour produire une image. Exécuter les callbacks requestAnimationFrame — JavaScript enregistré pour s'exécuter juste avant que l'image soit dessinée Calcul de style — calculer les valeurs CSS finales pour chaque élément Layout — calculer la position et la taille de chaque élément (aussi appelé reflow) Paint — générer des commandes de peinture décrivant quoi dessiner dans quelles couleurs Si rien n'a changé, ces étapes sont entièrement ignorées, donc elles ne s'exécutent pas nécessairement à chaque image. Seule l'étape finale de composition, qui prend la sortie produite et l'assemble à l'écran, est confiée au thread compositeur.

En d'autres termes, la majeure partie de la première moitié du pipeline qui dessine l'écran est la responsabilité du thread principal. Le pipeline de rendu pour mettre à jour l'écran Pour que l'écran paraisse fluide, les images doivent être dessinées au taux de rafraîchissement de l'affichage. Sur l'affichage 60Hz le plus courant, cela signifie 60 images par seconde, ou environ 16,6 millisecondes par image.

Et vous ne pouvez pas tout utiliser. Une fois le coût de traitement propre du navigateur soustrait, le budget pratique est généralement considéré comme étant d'environ 10 millisecondes, et sur un appareil 120Hz, le budget lui-même est divisé par deux. Le problème est que les deux types de travail ci-dessus se tiennent en file unique sur le même thread.

JavaScript a été conçu autour d'un modèle de boucle d'événements à thread unique. Le thread principal traite une tâche à la fois, et pendant que cette tâche s'exécute, rien d'autre ne peut se produire. Si une fonction JavaScript s'exécute pendant 200 millisecondes, alors pendant ces 200 millisecondes, le navigateur ne peut ni repeindre l'écran ni recevoir un clic de l'utilisateur.

Face à un budget d'image d'environ 10 millisecondes, c'est une quantité de temps fatale. Une tâche qui ru...