Optimisation pour les start-up JavaScript

Addy Osmani
Addy Osmani

Comme nous créons des sites de plus en plus dépendants de JavaScript, nous payons parfois pour ce que nous envoyons d'une manière que nous ne pouvons pas toujours voir facilement. Cet article vous explique pourquoi un peu de discipline peut vous aider si vous souhaitez que votre site se charge et soit interactif rapidement sur les appareils mobiles. Fournir moins de code JavaScript peut réduire le temps de transmission réseau, la décompression du code et l'analyse et la compilation de ce code JavaScript.

Lorsque la plupart des développeurs réfléchissent au coût de JavaScript, ils le considèrent en termes de coûts de téléchargement et d'exécution. L'envoi de plus d'octets JavaScript sur le réseau prend plus de temps, plus la connexion d'un utilisateur est lente.

Lorsqu'un navigateur demande une ressource, celle-ci doit être extraite, puis décompressée. Dans le cas de ressources telles que JavaScript, elles doivent être analysées et compilées avant l'exécution.

Cela peut poser problème, car le type de connexion réseau effectif dont dispose un utilisateur n'est pas nécessairement une connexion 3G, 4G ou Wi-Fi. Vous pouvez être connecté au Wi-Fi du café, mais être connecté à un point d'accès mobile avec un débit 2G.

Vous pouvez réduire le coût du transfert réseau lié à JavaScript de plusieurs façons:

  • Envoyez uniquement le code dont l'utilisateur a besoin.
    • La répartition du code vous permet de répartir votre code JavaScript en deux catégories, qui sont critiques et ce qui ne l'est pas. Les bundlers de modules tels que webpack sont compatibles avec la division de code.
    • Chargement différé dans du code non critique.
  • Minification
  • Compression
    • Utilisez au minimum gzip pour compresser les ressources textuelles.
    • Envisagez d'utiliser Brotli ~q11. Brotli est plus performant que gzip en termes de taux de compression. CertSimple a ainsi économisé 17% sur la taille des octets JS compressés et LinkedIn a économisé 4% sur ses temps de chargement.
  • Supprimer le code inutilisé
  • Mise en cache du code pour minimiser les trajets réseau.
    • Utilisez la mise en cache HTTP pour vous assurer que les navigateurs mettent efficacement en cache les réponses. Déterminez la durée de vie optimale des scripts (max-age) et fournissez des jetons de validation (ETag) pour éviter de transférer des octets inchangés.
    • La mise en cache des service workers rend le réseau de votre application résilient et vous permet d'accéder rapidement à des fonctionnalités telles que le cache de code V8.
    • Utilisez la mise en cache à long terme pour éviter d'avoir à récupérer à nouveau les ressources qui n'ont pas changé. Si vous utilisez Webpack, consultez la section Hachage de nom de fichier.

Analyser/Compiler

Une fois téléchargé, l'un des coûts les plus importants de JavaScript est le temps nécessaire à un moteur JavaScript pour analyser/compiler ce code. Dans Chrome DevTools, l'analyse et la compilation font partie de la période jaune "Script" du panneau "Performances".

ALT_TEXT_HERE

Les onglets "De bas en haut" et "Arborescence d'appel" indiquent les temps d'analyse/compilation exacts:

ALT_TEXT_HERE
Panneau "Performances" des outils pour les développeurs Chrome > Bas en haut. Lorsque les statistiques d'appel d'exécution de V8 sont activées, nous pouvons voir le temps passé par phases telles que l'analyse et la compilation.

Mais pourquoi est-ce important ?

ALT_TEXT_HERE

Si vous passez beaucoup de temps à analyser/compiler du code, vous risquez de retarder considérablement le délai d'interaction d'un utilisateur avec votre site. Plus vous envoyez de code JavaScript, plus il vous faudra de temps pour analyser et compiler le code avant que votre site ne soit interactif.

Octet par octet, JavaScript est plus coûteux à traiter par le navigateur que l'image de taille équivalente ou la police Web (Tom Dale)

Par rapport à JavaScript, le traitement d'images de taille équivalente engendre de nombreux coûts (ils doivent tout de même être décodés). Toutefois, en moyenne sur le matériel mobile, JavaScript est plus susceptible d'avoir un impact négatif sur l'interactivité d'une page.

ALT_TEXT_HERE
Les octets JavaScript et les octets d'image ont des coûts très différents. Les images ne bloquent généralement pas le thread principal ni n'empêchent les interfaces de devenir interactives lors du décodage et de la rastérisation. JS peut toutefois retarder l'interactivité en raison des coûts d'analyse, de compilation et d'exécution.

Lorsque l'analyse et la compilation sont lentes, le contexte est important : nous parlons ici de téléphones mobiles moyennes. L'utilisateur moyen peut disposer de téléphones avec des processeurs et des GPU lents, sans cache L2/L3 et qui peuvent même être limités en mémoire.

Les capacités du réseau et des appareils ne correspondent pas toujours. Un utilisateur disposant d'une connexion à fibre optique exceptionnelle ne dispose pas nécessairement du meilleur processeur pour analyser et évaluer le code JavaScript envoyé à son appareil. C'est également le cas à l'inverse : une connexion réseau horrible, mais un processeur extrêmement rapide. — Kristofer Baxter, LinkedIn

Vous pouvez voir ci-dessous le coût de l'analyse d'environ 1 Mo de code JavaScript décompressé (simple) sur du matériel bas et haut de gamme. Il existe un délai d'analyse/compilation de code deux à cinq fois supérieur entre les téléphones les plus rapides du marché et les téléphones moyens.

ALT_TEXT_HERE
Ce graphique met en évidence les temps d'analyse d'un bundle de 1 Mo de code JavaScript (environ 250 Ko compressé avec gzip) sur des ordinateurs et des appareils mobiles de classes différentes. Lorsque vous examinez le coût de l'analyse, vous devez prendre en compte les valeurs décompressées (par exemple, le fichier JS compressé avec gzip d'environ 250 Ko est décompressé jusqu'à environ 1 Mo de code).

Qu'en est-il d'un site réel, comme CNN.com ?

Sur l'iPhone 8 haut de gamme, il ne faut que 4 secondes pour analyser/compiler le code JS de CNN, contre environ 13 secondes pour un téléphone standard (Moto G4). Cela peut avoir un impact significatif sur la rapidité avec laquelle l'utilisateur peut interagir avec ce site.

ALT_TEXT_HERE
Ci-dessus, nous observons des temps d'analyse comparant les performances de la puce A11 Bionic d'Apple à celles du Snapdragon 617 sur du matériel Android moyen.

Cela souligne l'importance des tests sur du matériel moyenne (comme le Moto G4) plutôt que sur le téléphone qui pourrait se trouver dans votre poche. Toutefois, le contexte est important: optimisez vos campagnes en fonction des appareils et des conditions du réseau dont disposent vos utilisateurs.

ALT_TEXT_HERE
Google Analytics peut fournir des insights sur les classes d'appareils mobiles à partir desquelles les utilisateurs réels accèdent à votre site. Cela peut vous permettre de comprendre les contraintes réelles du processeur/GPU auxquelles ils opèrent.

Est-ce que nous envoyons vraiment trop de code JavaScript ? Euh, peut-être :)

En utilisant HTTP Archive (environ 500 000 premiers sites) pour analyser l'état de JavaScript sur mobile, nous pouvons constater que 50% des sites mettent plus de 14 secondes à devenir interactifs. Ces sites passent jusqu'à 4 secondes à analyser et compiler JS.

ALT_TEXT_HERE

Tenez compte du temps nécessaire à la récupération et au traitement de JavaScript et d'autres ressources. Il n'est peut-être pas surprenant que les utilisateurs patientent un certain temps avant de ressentir le sentiment que les pages sont prêtes à être utilisées. Nous pouvons certainement faire mieux ici.

La suppression du code JavaScript non critique de vos pages peut réduire les temps de transmission, les tâches d'analyse et de compilation gourmandes en ressources processeur, ainsi que la surcharge potentielle de la mémoire. Cela permet également d'accélérer l'interactivité de vos pages.

Durée d'exécution

L'analyse et la compilation ne se limitent pas à l'analyse des coûts. L'exécution JavaScript (exécuter du code une fois analysé/compilé) est l'une des opérations qui doivent se produire sur le thread principal. Les temps d'exécution longs peuvent également déterminer le délai d'interaction d'un utilisateur avec votre site.

ALT_TEXT_HERE

Si le script s'exécute pendant plus de 50 ms, le délai avant interactivité est retardé de la totalité du temps nécessaire au téléchargement, à la compilation et à l'exécution du JS – Alex Russell

Pour résoudre ce problème, JavaScript bénéficie d'un fonctionnement par petits fragments afin d'éviter de verrouiller le thread principal. Déterminez si vous pouvez réduire la quantité de travail effectuée pendant l'exécution.

Autres coûts

JavaScript peut avoir un impact sur les performances des pages de différentes façons:

  • Mémoire. Les pages peuvent sembler des à-coups ou se mettre souvent en pause en raison de la récupération de mémoire. Lorsqu'un navigateur récupère de la mémoire, l'exécution JS est suspendue. Ainsi, un navigateur collectant fréquemment de la mémoire peut suspendre l'exécution plus souvent que nous ne le souhaitons. Évitez les fuites de mémoire et les pauses gc fréquentes pour éviter les à-coups sur vos pages.
  • Pendant l'exécution, le code JavaScript de longue durée peut bloquer le thread principal et empêcher les pages de répondre. Diviser le travail en plus petits éléments (à l'aide de requestAnimationFrame() ou requestIdleCallback() pour la planification) peut réduire les problèmes de réactivité, ce qui peut améliorer l'Interaction to Next Paint (INP).

Modèles de réduction des frais de diffusion JavaScript

Lorsque vous essayez de ralentir l'analyse/la compilation et la transmission réseau pour JavaScript, certains modèles peuvent vous aider, comme la fragmentation basée sur le routage ou PRPL.

PRPL

Le modèle PRPL (Push, Render, Pre-cache, Lazy-load) optimise l'interactivité via une division du code et une mise en cache agressives:

ALT_TEXT_HERE

Voyons l'impact que cela peut avoir.

Nous analysons le temps de chargement des sites mobiles et des progressive web apps populaires à l'aide des statistiques d'appel d'exécution de V8. Comme vous pouvez le constater, le temps d'analyse (indiqué en orange) représente une part importante du temps passé par un grand nombre de ces sites:

ALT_TEXT_HERE

Wego, un site qui utilise PRPL, parvient à maintenir une durée d'analyse faible pour ses itinéraires, ce qui devient interactif très rapidement. De nombreux autres sites mentionnés ci-dessus ont adopté la répartition du code et les budgets de performances pour essayer de réduire leurs coûts JavaScript.

Amorçage progressif

De nombreux sites optimisent la visibilité du contenu au prix élevé de l'interactivité. Pour obtenir un premier aperçu rapide lorsque vous disposez de groupes JavaScript volumineux, les développeurs utilisent parfois le rendu côté serveur, puis le "mettent à niveau" pour associer des gestionnaires d'événements lorsque le code JavaScript est finalement récupéré.

Attention, cette opération a ses propres coûts. Vous 1) envoyez généralement une réponse HTML plus grande qui peut pousser notre interactivité, 2) vous pouvez laisser l'utilisateur dans une vallée étrange où la moitié de l'expérience ne peut pas être réellement interactive tant que le traitement JavaScript n'est pas terminé.

L'amorçage progressif peut être une meilleure approche. Envoyez vers le bas une page fonctionnelle minimale (composée uniquement du code HTML/JS/CSS nécessaire pour l'itinéraire actuel). À mesure que de nouvelles ressources arrivent, l'application peut se charger en différé et débloquer davantage de fonctionnalités.

ALT_TEXT_HERE
Amorçage progressif par Paul Lewis

Le chargement d'un code proportionnel à ce qui est visible est le Saint Graal. Les modèles PRPL et amorçage progressif permettent d'atteindre cet objectif.

Conclusions

La taille de transmission est essentielle pour les réseaux d'entrée de gamme. Le temps d'analyse est important pour les appareils liés au processeur. Il est important de garder le cap.

Les équipes ont réussi à adopter des budgets de performances stricts pour limiter la transmission JavaScript et les temps d'analyse/compilation. Consultez le livre d'Alex Russell, "Can You Afford It?: Realworld Web PerformanceBudgets (Budgets de performances Web réels) pour obtenir des conseils sur les budgets pour les mobiles.

ALT_TEXT_HERE
Il est utile de prendre en compte la marge de progression de JS que les décisions architecturales que nous prenons peuvent nous laisser pour la logique de l'application.

Si vous concevez un site qui cible les appareils mobiles, faites de votre mieux pour le développer sur du matériel représentatif, limitez les temps d'analyse/compilation JavaScript et adoptez un budget de performances pour que votre équipe puisse garder un œil sur ses coûts liés à JavaScript.

En savoir plus