Au cours des derniÚres années, ce qu'on appelle le «
prix JavaScript » a connu des changements positifs majeurs en raison de la vitesse d'analyse accrue et de la compilation de scripts par le navigateur. Maintenant, en 2019, les principaux composants de la charge sur les systÚmes créés par JavaScript sont le temps de chargement des scripts et leur temps d'exécution.

L'interaction de l'utilisateur avec le site peut ĂȘtre temporairement interrompue si le navigateur est occupĂ© Ă exĂ©cuter du code JavaScript. En consĂ©quence, nous pouvons dire que l'optimisation des goulots d'Ă©tranglement associĂ©s au chargement et Ă l'exĂ©cution de scripts peut avoir un fort impact positif sur les performances du site Web.
Directives pratiques générales pour l'optimisation de sites Web
Que signifie ce qui précÚde pour les développeurs Web? Le point ici est que le coût des ressources pour l'analyse (analyse, analyse) et la compilation de scripts ne sont pas aussi graves qu'auparavant. Par conséquent, lors de l'analyse et de l'optimisation des bundles JavaScript, les développeurs doivent prendre en compte les trois recommandations suivantes:
- Essayez de réduire le temps requis pour télécharger les scripts.
- Essayez de garder vos bundles JS petits. Ceci est particuliÚrement important pour les sites conçus pour les appareils mobiles. L'utilisation de petits ensembles améliore le temps de chargement du code, réduit le niveau d'utilisation de la mémoire et réduit la charge du processeur.
- Essayez d'empĂȘcher que tout le code du projet soit prĂ©sentĂ© comme un seul gros paquet. Si la taille du paquet dĂ©passe environ 50 Ă 100 Ko - divisez-le en fragments sĂ©parĂ©s de petite taille. GrĂące au multiplexage HTTP / 2, plusieurs demandes de serveur et plusieurs rĂ©ponses peuvent ĂȘtre traitĂ©es simultanĂ©ment. Cela rĂ©duit la charge sur le systĂšme associĂ©e Ă la nĂ©cessitĂ© de rĂ©pondre Ă des demandes supplĂ©mentaires de chargement de donnĂ©es.
- Si vous travaillez sur un projet mobile, essayez de garder le code aussi petit que possible. Cette recommandation est associée à de faibles débits de données sur les réseaux mobiles. De plus, efforcez-vous d'utiliser économiquement la mémoire.
- Essayez de réduire le temps nécessaire à l'exécution des scripts.
- Ăvitez d'utiliser des tĂąches longues qui peuvent charger le thread principal pendant une longue pĂ©riode et augmenter le temps nĂ©cessaire pour que les pages soient dans un Ă©tat dans lequel les utilisateurs peuvent interagir avec eux. Dans l'environnement actuel, les scripts qui s'exĂ©cutent aprĂšs leur chargement apportent une contribution majeure au «prix de JavaScript».
- N'intégrez pas d'extraits de code volumineux dans les pages.
- La rĂšgle suivante doit ĂȘtre respectĂ©e ici: si la taille du script dĂ©passe 1 Ko, essayez de ne pas l'intĂ©grer dans le code de la page. L'une des raisons de cette recommandation est le fait que 1 Ko est la limite aprĂšs laquelle la mise en cache du code de script externe commence Ă fonctionner dans Chrome. Gardez Ă©galement Ă l'esprit que l'analyse et la compilation de scripts intĂ©grĂ©s sont toujours en cours d'exĂ©cution dans le thread principal.
Pourquoi est-il si important de charger et d'exécuter des scripts?
Pourquoi est-il important d'optimiser le temps de chargement et d'exĂ©cution des scripts dans des conditions modernes? Les temps de chargement des scripts sont extrĂȘmement importants dans les situations oĂč les sites sont accessibles via des rĂ©seaux lents. MalgrĂ© le fait que les rĂ©seaux 4G (et mĂȘme 5G) se rĂ©pandent de plus en plus, la propriĂ©tĂ©
NetworkInformation.effectiveType dans de nombreux cas d'utilisation de connexions Internet mobiles affiche des indicateurs qui se situent au niveau des rĂ©seaux 3G ou mĂȘme Ă des niveaux infĂ©rieurs.
Le temps requis pour exécuter le code JS est important pour les appareils mobiles avec des processeurs lents. En raison du fait que les appareils mobiles utilisent des CPU et GPU différents, du fait que lorsque les appareils surchauffent, afin de les protéger, les performances de leurs composants diminuent, vous pouvez observer un écart important entre les performances des téléphones et tablettes chers et bon marché. Cela affecte considérablement les performances du code JavaScript, car la capacité à exécuter ce code par un périphérique est limitée par les capacités du processeur de ce périphérique.
En fait, si nous analysons le temps total consacrĂ© au chargement et Ă la prĂ©paration de la page pour le travail dans un navigateur comme Chrome, environ 30% de ce temps peut ĂȘtre consacrĂ© Ă l'exĂ©cution du code JS. Vous trouverez ci-dessous une analyse du chargement d'une page Web trĂšs typique (reddit.com) sur un ordinateur de bureau hautes performances.
Dans le processus de chargement de la page, environ 10 Ă 30% du temps est consacrĂ© Ă l'exĂ©cution de code Ă l'aide de V8Si nous parlons d'appareils mobiles, alors sur un tĂ©lĂ©phone moyen (Moto G4), il faut 3 Ă 4 fois plus de temps pour exĂ©cuter reddit.com sur un code JS que sur un appareil de haut niveau (Pixel 3). Sur un appareil faible (Alcatel 1X coĂ»tant moins de 100 $), rĂ©soudre le mĂȘme problĂšme nĂ©cessite au moins 6 fois plus de temps que quelque chose comme Pixel 3.
Le temps requis pour traiter le code JS sur des appareils mobiles de différentes classesVeuillez noter que les versions mobile et bureau de reddit.com sont différentes. Par conséquent, vous ne pouvez pas comparer les résultats des appareils mobiles et, par exemple, du MacBook Pro.
Lorsque vous essayez d'optimiser le temps d'exécution du code JavaScript, faites attention aux
tĂąches longues qui peuvent capturer le flux d'interface utilisateur pendant une longue pĂ©riode. Ces tĂąches peuvent entraver l'exĂ©cution d'autres tĂąches extrĂȘmement importantes, mĂȘme lorsque l'apparence de la page semble complĂštement prĂȘte pour le travail. Les tĂąches Ă long terme doivent ĂȘtre dĂ©composĂ©es en tĂąches plus petites. En divisant le code en parties et en contrĂŽlant l'ordre de chargement de ces parties, vous pouvez obtenir le fait que les pages atteindront un Ă©tat interactif plus rapidement. EspĂ©rons que cela conduira les utilisateurs Ă moins d'inconvĂ©nients Ă interagir avec les pages.
Les tĂąches de longue durĂ©e capturent le thread principal. Ils doivent ĂȘtre brisĂ©s en morceauxComment les amĂ©liorations V8 accĂ©lĂšrent-elles l'analyse et la compilation des scripts?
La vitesse d'analyse du code JS source dans la V8, depuis l'Ă©poque de Chrome 60, a Ă©tĂ© multipliĂ©e par 2. Dans le mĂȘme temps, l'analyse et la compilation contribuent dĂ©sormais moins au «prix JavaScript». Cela est dĂ» Ă d'autres efforts d'optimisation de Chrome menant Ă la parallĂ©lisation de ces tĂąches.
Dans la V8, la quantitĂ© de travail sur l'analyse et la compilation de code produite dans le thread principal est rĂ©duite en moyenne de 40%. Par exemple, pour Facebook, l'amĂ©lioration de cet indicateur Ă©tait de 46%, pour Pinterest - 62%. Le rĂ©sultat le plus Ă©levĂ©, 81%, a Ă©tĂ© obtenu pour YouTube. Ces rĂ©sultats sont possibles du fait que l'analyse et la compilation sont dĂ©placĂ©es vers un flux distinct. Et cela s'ajoute aux amĂ©liorations existantes concernant la solution de streaming des mĂȘmes tĂąches en dehors du flux principal.
Temps d'analyse JS dans diffĂ©rentes versions de ChromeVous pouvez Ă©galement visualiser comment les optimisations V8 produites dans diffĂ©rentes versions de Chrome affectent le temps processeur requis pour traiter le code. En mĂȘme temps que Chrome 61 devait analyser le code Facebook JS, Chrome 75 peut dĂ©sormais analyser le code Facebook JS et, en outre, analyser le code Twitter 6 fois.
Pendant que Chrome 61 avait besoin de traiter le code Facebook JS, Chrome 75 peut traiter Ă la fois le code Facebook et six fois la quantitĂ© de code Twitter.Parlons de la façon dont ces amĂ©liorations ont Ă©tĂ© rĂ©alisĂ©es. En rĂ©sumĂ©, les ressources de script peuvent ĂȘtre analysĂ©es et compilĂ©es en mode streaming dans le workflow. Cela signifie ce qui suit:
- V8 peut analyser et compiler du code JS sans bloquer le thread principal.
- Le traitement de flux du script démarre lorsque l'analyseur HTML universel rencontre la
<script>
. Un analyseur HTML gÚre les scripts qui bloquent l'analyse des pages. Rencontre avec des scripts asynchrones, il continue de travailler. - Dans la plupart des scénarios du monde réel, caractérisés par certaines vitesses de connexion réseau, le V8 analyse le code plus rapidement qu'il ne peut le charger. En conséquence, V8 termine les tùches d'analyse et de compilation du code quelques millisecondes aprÚs le chargement des derniers octets du script.
Si vous en parlez un peu plus en dĂ©tail, le point ici est le suivant. Dans les versions beaucoup plus anciennes de Chrome, le script devait ĂȘtre tĂ©lĂ©chargĂ© dans son intĂ©gralitĂ© avant de l'analyser. Cette approche est simple et comprĂ©hensible, mais lorsqu'elle est utilisĂ©e, les ressources du processeur sont utilisĂ©es de maniĂšre irrationnelle. Chrome, entre les versions 41 et 68, commence l'analyse en mode asynchrone, immĂ©diatement aprĂšs le chargement du script, effectuant cette tĂąche dans un thread distinct.
Les scripts sont envoyés au navigateur en fragments. La V8 démarre le traitement des données en continu aprÚs avoir au moins 30 Ko de code.Dans Chrome 71, nous sommes passés à un systÚme basé sur les tùches. Ici, le planificateur peut démarrer simultanément plusieurs sessions de traitement de script asynchrones / retardées. En raison de ce changement, la charge créée par l'analyse du thread principal a diminué d'environ 20%. Cela a conduit à une amélioration d'environ 2% des scores TTI / FID obtenus sur des sites réels.
Chrome 71 utilise un systĂšme de traitement de code basĂ© sur les tĂąches. Avec cette approche, le planificateur peut traiter plusieurs scripts asynchrones / en attente en mĂȘme temps.Dans Chrome 72, nous avons fait du traitement en streaming le principal moyen d'analyser les scripts. DĂ©sormais, mĂȘme les scripts synchrones rĂ©guliers sont gĂ©rĂ©s de cette façon (bien que cela ne s'applique pas aux scripts intĂ©grĂ©s). De plus, nous avons cessĂ© d'annuler les opĂ©rations d'analyse basĂ©e sur les tĂąches si le thread principal avait besoin de code analysĂ©. Cela est dĂ» au fait que cela conduit Ă la nĂ©cessitĂ© de rĂ©exĂ©cuter une partie du travail dĂ©jĂ effectuĂ©.
La version précédente de Chrome était compatible avec l'analyse en continu et la compilation en continu de code. Ensuite, le script téléchargé à partir du réseau doit d'abord entrer dans le flux principal, puis il sera redirigé vers le systÚme de traitement de script de streaming.
Cela a souvent conduit l'analyseur de flux Ă attendre des donnĂ©es dĂ©jĂ tĂ©lĂ©chargĂ©es depuis le rĂ©seau mais pas encore redirigĂ©es par le flux principal vers le traitement de flux. Cela est dĂ» au fait que le thread principal peut ĂȘtre occupĂ© par d'autres tĂąches (telles que l'analyse HTML, la crĂ©ation d'une mise en page ou l'exĂ©cution de code JS).
Maintenant, nous essayons de commencer Ă analyser le code lors du prĂ©chargement des pages. Auparavant, la mise en Ćuvre d'un tel mĂ©canisme Ă©tait entravĂ©e par la nĂ©cessitĂ© d'utiliser les ressources du thread principal pour transfĂ©rer des tĂąches vers l'analyseur de streaming. Des dĂ©tails sur l'analyse du code JS qui s'exĂ©cute «instantanĂ©ment» peuvent ĂȘtre trouvĂ©s
ici .
Comment les amĂ©liorations ont-elles affectĂ© ce qui peut ĂȘtre vu dans les outils du dĂ©veloppeur?
En plus de ce qui précÚde, on peut noter qu'il y avait un
problÚme dans les outils de développement auparavant. Cela consistait dans le fait que les informations sur la tùche d'analyse étaient affichées comme si elles bloquaient complÚtement le thread principal. Cependant, l'analyseur a effectué des opérations bloquant le thread principal uniquement lorsqu'il avait besoin de nouvelles données. Depuis que nous sommes passés du schéma d'utilisation d'un flux unique pour le traitement en continu des données au schéma dans lequel les tùches de traitement en streaming sont appliquées, cela est devenu assez évident. Voici ce que vous pouvez voir dans Chrome 69.
Le problÚme réside dans les outils de développement, en raison desquels les informations sur l'analyse des scripts ont été affichées comme si elles bloquaient complÚtement le thread principalIci, vous pouvez voir que la tùche d'analyse du script prend 1,08 seconde. Mais l'analyse de JavaScript n'est en fait pas si lente! La plupart du temps, rien d'utile n'est effectué, à part attendre les données du thread principal.
Dans Chrome 76, vous pouvez déjà voir une image complÚtement différente.
Dans Chrome 76, l'analyse est divisée en de nombreuses petites tùchesEn général, on peut noter que l'onglet Performances des outils de développement est idéal pour voir l'image globale de ce qui se passe sur la page. Afin d'obtenir des informations plus détaillées qui reflÚtent les fonctionnalités de la V8, telles que le temps d'analyse et le temps de compilation, vous pouvez utiliser le suivi de Chrome avec la prise en charge RCS (Runtime Call Stats). Dans les données RCS reçues, vous pouvez trouver les indicateurs Parse-Background et Compile-Background. Ils peuvent signaler le temps qu'il a fallu pour analyser et compiler le code JS en dehors du thread principal. Les mesures Parse et Compile indiquent combien de temps a été consacré à des activités connexes dans le thread principal.
Analyse des données RCS à l'aide de Google TracingComment les changements ont-ils affecté le travail avec des sites réels?
Examinons quelques exemples de la façon dont le traitement de script en continu a influencé la navigation sur des sites réels.
âReddit
Affichez reddit.com sur un MacBook Pro. Temps d'analyse et de compilation du code JS passé dans les threads principal et de travailIl existe plusieurs bundles JS sur le site reddit.com, dont chacun dépasse 100 Ko. Ils sont enveloppés dans des fonctions externes, ce qui conduit à l'exécution de gros volumes de
compilation "paresseux" dans le thread principal. Le temps nécessaire pour traiter les scripts dans le thread principal est crucial dans le diagramme ci-dessus. Cela est dû au fait qu'une charge importante sur le thread principal peut augmenter le temps nécessaire pour que la page passe en mode interactif. Lors du traitement du code du site reddit.com, la plupart du temps est consacré au thread principal et les ressources du thread de travail / arriÚre-plan sont utilisées au minimum.
Vous pouvez optimiser ce site en divisant certains gros paquets en parties (environ 50 Ko chacun) et sans encapsuler le code dans une fonction. Cela maximiserait le traitement parallĂšle des scripts. En consĂ©quence, les bundles pouvaient ĂȘtre analysĂ©s et compilĂ©s en mĂȘme temps en mode streaming. Cela rĂ©duirait la charge sur le thread principal lors de la prĂ©paration de la page pour le travail.
âFacebook
Affichez facebook.com sur votre MacBook Pro. Temps d'analyse et de compilation du code JS passĂ© dans les threads principal et de travailNous pouvons Ă©galement envisager un site comme facebook.com, qui utilise environ 6 Mo de code JS compressĂ©. Ce code est chargĂ© Ă l'aide d'environ 292 requĂȘtes. Certains d'entre eux sont asynchrones, certains visent Ă prĂ©charger des donnĂ©es, certains ont une faible prioritĂ©. La plupart des scripts Facebook sont de petite taille et Ă focalisation Ă©troite. Cela peut avoir un bon effet sur le traitement parallĂšle des donnĂ©es au moyen de flux d'arriĂšre-plan / de travail. Le fait est que de nombreux petits scripts peuvent ĂȘtre analysĂ©s et compilĂ©s en mĂȘme temps au moyen d'un traitement de script en continu.
Veuillez noter que votre site est probablement diffĂ©rent du site Facebook. Vous n'avez probablement pas d'applications qui restent ouvertes pendant longtemps (comme ce qu'est un site Facebook ou l'interface Gmail), et lorsque vous travaillez avec elles, le tĂ©lĂ©chargement de volumes de scripts aussi sĂ©rieux avec un navigateur de bureau peut ĂȘtre justifiĂ©. Mais, malgrĂ© cela, nous pouvons donner une recommandation gĂ©nĂ©rale qui soit juste pour tous les projets. Cela rĂ©side dans le fait qu'il vaut la peine de diviser le code d'application en paquets modestes et que vous ne devez tĂ©lĂ©charger ces paquets qu'en cas de besoin.
Bien que la plupart du travail d'analyse et de compilation du code JS puisse ĂȘtre effectuĂ© Ă l'aide d'outils de streaming dans un thread d'arriĂšre-plan, certaines opĂ©rations nĂ©cessitent toujours un thread principal. Lorsque le thread principal est occupĂ© par quelque chose, la page ne peut pas rĂ©pondre Ă l'interaction de l'utilisateur. Par consĂ©quent, il est recommandĂ© de prĂȘter attention Ă l'impact sur les sites UX du chargement et de l'exĂ©cution du code JS.
Gardez à l'esprit que tous les moteurs et navigateurs JavaScript ne diffusent plus de scripts et optimisent leur chargement. Mais malgré cela, nous espérons que les principes généraux d'optimisation décrits ci-dessus peuvent améliorer l'expérience utilisateur de travailler avec des sites consultés dans l'un des navigateurs existants.
Prix ââd'analyse JSON
L'analyse du code JSON peut ĂȘtre beaucoup plus efficace que l'analyse du code JavaScript. Le fait est que la grammaire JSON est beaucoup plus simple que la grammaire JavaScript. Ces connaissances peuvent ĂȘtre appliquĂ©es afin d'amĂ©liorer la vitesse de prĂ©paration pour le travail des applications Web qui utilisent de gros objets de configuration (tels que les rĂ©fĂ©rentiels Redux), dont la structure ressemble au code JSON. Par consĂ©quent, il s'avĂšre qu'au lieu de prĂ©senter les donnĂ©es comme des littĂ©raux d'objet incorporĂ©s dans le code, vous pouvez les reprĂ©senter comme des chaĂźnes d'objets JSON et analyser ces objets lors de l'exĂ©cution.
La premiĂšre approche, utilisant des objets JS, ressemble Ă ceci:
const data = { foo: 42, bar: 1337 };
La deuxiĂšme approche, utilisant des chaĂźnes JSON, implique l'utilisation de telles constructions:
const data = JSON.parse('{"foo":42,"bar":1337}');
Comme vous n'avez besoin d'exécuter le traitement de chaßne JSON qu'une seule fois, l'approche qui utilise
JSON.parse
est beaucoup plus rapide que l'utilisation de littĂ©raux d'objet JavaScript. Surtout - lors du chargement de page "Ă froid". Il est recommandĂ© d'utiliser des chaĂźnes JSON pour reprĂ©senter les objets commençant Ă 10 Ko. Cependant, comme pour tout conseil de performance, ce conseil ne doit pas ĂȘtre suivi sans rĂ©flĂ©chir. Avant d'appliquer cette technique de prĂ©sentation des donnĂ©es en production, il est nĂ©cessaire de faire des mesures et d'Ă©valuer son impact rĂ©el sur le projet.
L'utilisation de littĂ©raux d'objets comme stockage pour de grandes quantitĂ©s de donnĂ©es constitue une autre menace. Le fait est qu'il existe un risque que ces littĂ©raux puissent ĂȘtre traitĂ©s deux fois:
- La premiÚre passe de traitement est effectuée avec une analyse préliminaire du littéral.
- La deuxiÚme approche est effectuée lors de l'analyse "paresseuse" du littéral.
Vous ne pouvez pas vous dĂ©barrasser de la premiĂšre passe de traitement des littĂ©raux d'objet. Mais, heureusement, la deuxiĂšme passe peut ĂȘtre Ă©vitĂ©e en plaçant les littĂ©raux d'objet au niveau supĂ©rieur ou Ă l'intĂ©rieur de
PIFE .
Qu'en est-il de l'analyse et de la compilation de code lors de visites répétées sur des sites?
Il est possible d'optimiser les performances du site dans les cas oĂč les utilisateurs les visitent plusieurs fois, grĂące aux capacitĂ©s V8 de mise en cache du code et du bytecode. Lorsqu'un script est demandĂ© au serveur pour la premiĂšre fois, Chrome le tĂ©lĂ©charge et passe la V8 pour la compilation. Le navigateur enregistre en outre le fichier de ce script dans son cache disque. Lorsque la deuxiĂšme demande de tĂ©lĂ©chargement du mĂȘme fichier JS est exĂ©cutĂ©e, Chrome le prend dans le cache du navigateur et passe Ă nouveau V8 pour la compilation. Cette fois, cependant, le code compilĂ© est sĂ©rialisĂ© et attachĂ© au fichier de script mis en cache en tant que mĂ©tadonnĂ©es.
SystĂšme de mise en cache de code dans V8Lorsque le script est demandĂ© pour la troisiĂšme fois, Chrome prend le fichier et ses mĂ©tadonnĂ©es du cache, puis transfĂšre le V8 Ă la fois. La V8 dĂ©sĂ©rialise les mĂ©tadonnĂ©es et, par consĂ©quent, peut ignorer l'Ă©tape de compilation. La mise en cache du code est dĂ©clenchĂ©e si les visites sur le site sont effectuĂ©es dans les 72 heures. Chrome utilise Ă©galement la stratĂ©gie de mise en cache de code gourmande lorsqu'un employĂ© de service est utilisĂ© pour mettre en cache des scripts. Des dĂ©tails sur la mise en cache du code peuvent ĂȘtre trouvĂ©s
ici .
Résumé
En 2019, les principaux goulots d'Ă©tranglement des performances des pages Web sont le chargement et l'exĂ©cution de scripts. Afin d'amĂ©liorer la situation, efforcez-vous d'utiliser des scripts synchrones (intĂ©grĂ©s) de petites tailles, qui sont nĂ©cessaires pour organiser l'interaction de l'utilisateur avec la partie de la page qui lui est visible immĂ©diatement aprĂšs le chargement. Il est recommandĂ© de charger les scripts utilisĂ©s pour traiter d'autres parties des pages en mode diffĂ©rĂ©. Brisez les gros paquets en petits morceaux. Cela facilitera la mise en Ćuvre d'une stratĂ©gie pour travailler avec du code, dans l'application duquel le code n'est chargĂ© que lorsqu'il est nĂ©cessaire, et uniquement lĂ oĂč il est nĂ©cessaire. Cela maximisera les capacitĂ©s de V8, visant Ă un traitement parallĂšle du code.
Si vous dĂ©veloppez des projets mobiles, vous devez vous assurer qu'ils utilisent le moins de code JS possible. Cette recommandation dĂ©coule du fait que les appareils mobiles fonctionnent gĂ©nĂ©ralement dans des rĂ©seaux assez lents. De tels pĂ©riphĂ©riques, en outre, peuvent ĂȘtre limitĂ©s en termes de RAM disponible et de ressources processeur disponibles. Essayez de trouver un Ă©quilibre entre le temps requis pour prĂ©parer les scripts tĂ©lĂ©chargĂ©s depuis le rĂ©seau et l'utilisation du cache. Cela maximisera la quantitĂ© d'analyse et de compilation de code effectuĂ©e en dehors du thread principal.
Chers lecteurs! Optimisez-vous vos projets web en tenant compte des particularités du traitement de code JS par les navigateurs modernes?
