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.
Réseau
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.
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
- Utilisez UglifyJS pour réduire la taille du code ES5.
- Utilisez babel-minify ou uglify-es pour réduire la taille d'ES2015+.
- Compression
- Supprimer le code inutilisé
- Identifiez les possibilités de suppression ou de chargement différé du code avec la couverture de code DevTools.
- Utilisez babel-preset-env et browserlist pour éviter de transpiler les fonctionnalités déjà disponibles dans les navigateurs modernes. Les développeurs expérimentés peuvent trouver qu'une analyse minutieuse de leurs bundles de Webpack les aide à identifier les possibilités d'éliminer les dépendances inutiles.
- Pour supprimer du code, consultez tree-shaking, les optimisations avancées de Closure Compiler et les plug-ins de coupe de bibliothèque tels que lodash-babel-plugin ou le ContextReplacementPlugin pour les bibliothèques telles que Moment.js.
- 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".
Les onglets "De bas en haut" et "Arborescence d'appel" indiquent les temps d'analyse/compilation exacts:
Mais pourquoi est-ce important ?
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.
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.
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.
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.
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.
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.
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()
ourequestIdleCallback()
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:
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:
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.
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.
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
- Sommet des développeurs Chrome 2017 : bonnes pratiques concernant le chargement moderne
- Performances au démarrage JavaScript
- Solving the Web performance crisis – Nolan Lawson
- Pouvez-vous vous le permettre ? Budgets de performances réelles – Alex Russell
- Évaluer les frameworks et les bibliothèques Web : Kristofer Baxter
- Consultez les résultats de Cloudflare en testant la compression avec Brotli (notez que les Brotli dynamiques de meilleure qualité peuvent retarder le rendu initial de la page, alors évaluez-les attentivement). Vous préférez probablement effectuer une compression statique.)
- Performance Futures – Sam Saccone