Optimisation pour les start-up JavaScript

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

Réseau

Lorsque la plupart des développeurs pensent au coût de JavaScript, ils le font en termes de coût de téléchargement et d'exécution. Plus la connexion d'un utilisateur est lente, plus l'envoi d'octets de code JavaScript sur le réseau prend du temps.

Lorsqu'un navigateur demande une ressource, celle-ci doit être récupérée, 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 d'un utilisateur peut ne pas être la 3G, la 4G ou le Wi-Fi. Vous pouvez être connecté au Wi-Fi d'un café, mais à un point d'accès mobile avec des débits 2G.

Vous pouvez réduire les coûts de transfert réseau du code JavaScript en procédant comme suit:

  • Envoyer uniquement le code dont l'utilisateur a besoin
    • Utilisez le fractionnement du code pour diviser votre code JavaScript en éléments essentiels et non essentiels. Les outils de regroupement de modules tels que webpack sont compatibles avec le fractionnement du code.
    • Chargement différé du code non critique.
  • Minimisation
  • 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. Cela a permis à CertSimple de réduire la taille des octets JS compressés de 17% et à LinkedIn de réduire ses temps de chargement de 4%.
  • Supprimez le code inutilisé.
  • Mettre en cache le code pour réduire le nombre de requêtes réseau
    • Utilisez la mise en cache HTTP pour vous assurer que les navigateurs mettent en cache les réponses de manière efficace. Déterminez les durées de vie optimales pour les scripts (max-age) et les jetons de validation de l'offre (ETag) afin d'éviter de transférer des octets inchangés.
    • La mise en cache du service worker peut rendre le réseau de votre application résilient et vous donner un accès anticipé à des fonctionnalités telles que le cache de code de V8.
    • Utilisez la mise en cache à long terme pour éviter d'avoir à récupérer à nouveau des 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 lourds de JavaScript est le temps qu'un moteur JS met à analyser/compiler ce code. Dans Chrome DevTools, l'analyse et la compilation font partie du temps "Scripting" jaune dans le panneau "Performances".

ALT_TEXT_HERE

Les onglets "Bottom-Up" (De bas en haut) et "Call Tree" (Arborescence des appels) affichent les délais d'analyse/compilation exacts:

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

Mais pourquoi est-ce important ?

ALT_TEXT_HERE

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

Pour chaque octet, le traitement de JavaScript par le navigateur est plus coûteux que celui de l'image ou de la police Web de taille équivalente. – Tom Dale

Par rapport à JavaScript, le traitement d'images de taille équivalente implique de nombreux coûts (elles doivent toujours être décodées), mais sur les appareils mobiles moyens, JS est plus susceptible d'avoir un impact négatif sur l'interactivité d'une page.

ALT_TEXT_HERE
Les coûts des octets JavaScript et des images sont très différents. En général, les images ne bloquent pas le thread principal ni n'empêchent les interfaces d'être interactives pendant le décodage et la rastérisation. Toutefois, le code JavaScript peut retarder l'interactivité en raison des coûts d'analyse, de compilation et d'exécution.

Lorsque nous parlons de la lenteur de l'analyse et de la compilation, le contexte est important. Nous parlons ici de téléphones mobiles moyens. Les utilisateurs moyens peuvent avoir des 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 fonctionnalités du réseau et celles de l'appareil ne correspondent pas toujours. Un utilisateur disposant d'une connexion Fiber exceptionnelle n'a pas nécessairement le meilleur processeur pour analyser et évaluer le code JavaScript envoyé à son appareil. Cela est également vrai dans le sens inverse : une connexion réseau terrible, mais un processeur ultra-rapide. — Kristofer Baxter, LinkedIn

Vous trouverez ci-dessous le coût de l'analyse d'environ 1 Mo de code JavaScript décompressé (simple) sur du matériel bas de gamme et haut de gamme. Le temps d'analyse/compilation du code varie de 2 à 5 fois 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 JavaScript de 1 Mo (environ 250 Ko compressé en gzip) sur des ordinateurs de bureau et des appareils mobiles de différentes classes. Lorsque vous examinez le coût de l'analyse, vous devez tenir compte des chiffres décompressés.Par exemple, environ 250 ko de code JavaScript gzippé se décompressent en 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 JavaScript de CNN, contre 13 secondes pour un téléphone moyen (Moto G4). Cela peut avoir un impact important sur la rapidité avec laquelle un utilisateur peut interagir pleinement avec ce site.

ALT_TEXT_HERE
Vous pouvez voir ci-dessus les temps d'analyse comparant les performances de la puce A11 Bionic d'Apple au Snapdragon 617 sur un matériel Android plus moyen.

Cela souligne l'importance de tester sur du matériel moyen (comme le Moto G4) plutôt que sur le téléphone que vous avez peut-être dans votre poche. Le contexte est toutefois important: optimisez pour les conditions de l'appareil et du réseau de vos utilisateurs.

ALT_TEXT_HERE
Google Analytics peut vous fournir des insights sur les classes d'appareils mobiles avec lesquels vos utilisateurs réels accèdent à votre site. Cela peut permettre de comprendre les contraintes réelles du processeur/GPU avec lesquelles ils travaillent.

Envoyons-nous vraiment trop de code JavaScript ? Euh, peut-être :)

En utilisant HTTP Archive (environ 500 000 sites populaires) pour analyser l'état de JavaScript sur mobile, nous constatons que 50% des sites mettent plus de 14 secondes à devenir interactifs. Ces sites passent jusqu'à quatre secondes à analyser et compiler du code JavaScript.

ALT_TEXT_HERE

Compte tenu du temps nécessaire pour extraire et traiter le code JavaScript et d'autres ressources, il n'est peut-être pas surprenant que les utilisateurs doivent attendre un certain temps avant de sentir que les pages sont prêtes à l'emploi. Nous pouvons certainement faire mieux.

Supprimer le code JavaScript non critique de vos pages peut réduire les temps de transmission, l'analyse et la compilation gourmande en processeur, ainsi que les coûts de mémoire potentiels. Cela permet également de rendre vos pages interactives plus rapidement.

Durée d'exécution

L'analyse et la compilation ne sont pas les seules opérations qui peuvent avoir un coût. L'exécution JavaScript (code d'exécution une fois analysé/compilé) est l'une des opérations qui doivent se produire sur le thread principal. Des temps d'exécution longs peuvent également retarder le moment où un utilisateur peut interagir avec votre site.

ALT_TEXT_HERE

Si l'exécution du script dure plus de 50 ms, le délai d'interactivité est retardé par la durée complète nécessaire pour télécharger, compiler et exécuter le code JavaScript. – Alex Russell

Pour y remédier, il est préférable que JavaScript soit divisé en petits blocs afin d'éviter de bloquer le thread principal. Essayez de réduire la quantité de travail effectuée pendant l'exécution.

Autres frais

JavaScript peut également avoir un impact sur les performances des pages:

  • Mémoire Les pages peuvent sembler saccadées ou s'arrêter fréquemment en raison de la récupération de mémoire. Lorsqu'un navigateur récupère de la mémoire, l'exécution JavaScript est mise en pause. Un navigateur qui effectue fréquemment une récupération de mémoire peut donc mettre en pause l'exécution plus fréquemment que nous le souhaiterions. Évitez les fuites de mémoire et les pauses de récupération de mémoire fréquentes pour éviter les à-coups sur les pages.
  • Lors de l'exécution, le code JavaScript de longue durée peut bloquer le thread principal, ce qui entraîne des pages qui ne répondent pas. Décomposer le travail en petites parties (à l'aide de requestAnimationFrame() ou requestIdleCallback() pour la planification) peut réduire les problèmes de réactivité, ce qui peut contribuer à améliorer l'Interaction to Next Paint (INP).

Modèles permettant de réduire les coûts de diffusion JavaScript

Lorsque vous essayez de ralentir les temps d'analyse/compilation et de transmission réseau pour JavaScript, certains modèles peuvent vous aider, comme le découpage basé sur les routes ou PRPL.

PRPL

PRPL (Push, Render, Pre-cache, Lazy-load) est un modèle qui optimise l'interactivité grâce à un fractionnement et un mise en cache du code agressifs:

ALT_TEXT_HERE

Voyons l'impact qu'elle peut avoir.

Nous analysons le temps de chargement des sites mobiles populaires et des applications Web progressives à l'aide des statistiques d'appel d'exécution de V8. Comme vous pouvez le constater, la durée d'analyse (en orange) représente une part importante du temps passé par de nombreux sites:

ALT_TEXT_HERE

Wego, un site qui utilise PRPL, parvient à maintenir un temps d'analyse faible pour ses itinéraires, ce qui le rend très interactif. De nombreux autres sites ci-dessus ont adopté le fractionnement du code et les budgets de performances pour essayer de réduire leurs coûts en JS.

Amorçage progressif

De nombreux sites optimisent la visibilité du contenu au détriment de l'interactivité. Pour obtenir une première peinture rapide lorsque vous disposez de grands groupes JavaScript, les développeurs utilisent parfois le rendu côté serveur, puis le "mettront à niveau" pour associer des gestionnaires d'événements lorsque le code JavaScript sera finalement extrait.

Attention, cela entraîne des coûts. Vous 1) envoyez généralement une réponse HTML plus importante, ce qui peut accroître l'interactivité, 2) pouvez laisser l'utilisateur dans une vallée étrange où la moitié de l'expérience ne peut pas être interactive tant que JavaScript n'a pas terminé le traitement.

Le bootstrapping progressif peut être une meilleure approche. Envoyez 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 charger de manière différée et déverrouiller d'autres fonctionnalités.

ALT_TEXT_HERE
Progressive Bootstrapping par Paul Lewis

Le chargement de code proportionnel à ce qui est visible est le Saint Graal. PRPL et le démarrage progressif sont des modèles qui peuvent vous y aider.

Conclusions

La taille de transmission est essentielle pour les réseaux bas de gamme. Le temps d'analyse est important pour les appareils liés au processeur. Il est important de les maintenir à un niveau bas.

Les équipes ont réussi à adopter des budgets de performances stricts pour réduire les temps de transmission et d'analyse/compilation JavaScript. Consultez Can You Afford It? "Budgets de performances Web réels" pour obtenir des conseils sur les budgets pour les mobiles.

ALT_TEXT_HERE
Il est utile de réfléchir à la quantité de "marge de manœuvre" JavaScript que les décisions d'architecture que nous prenons peuvent nous laisser pour la logique de l'application.

Si vous créez un site qui cible les appareils mobiles, faites de votre mieux pour développer sur du matériel représentatif, réduisez les temps d'analyse/compilation JavaScript et adoptez un budget de performances pour vous assurer que votre équipe peut surveiller ses coûts JavaScript.

En savoir plus