
Réduire le temps d'exécution JavaScript : envoyer moins, puis différer, puis découper
- vuetelemetry
- Guides
- 8 min de lecture
Lighthouse donne le chiffre, mais la correction n'est presque jamais dans votre propre code. L'essentiel du temps d'exécution revient aux dépendances qui tournent avant que rien ne soit visible. Trois gestes, dans l'ordre qui fonctionne vraiment, et la seule mesure à prendre d'abord.
Lighthouse vous dit que l'exécution JavaScript a pris 3,4 secondes et propose une liste de fichiers. Le réflexe est d'ouvrir votre propre code et d'optimiser des boucles. C'est presque toujours le mauvais endroit, et la raison est arithmétique : dans une application typique, votre code ne représente qu'une petite part des octets que le navigateur analyse, compile et exécute.
Le temps d'exécution, ce sont trois coûts distincts que les outils affichent comme un seul. L'analyse transforme le texte en arbre syntaxique abstrait, la compilation en fait du bytecode, et l'évaluation l'exécute réellement. Les trois augmentent avec la quantité de JavaScript envoyée, et c'est pourquoi le premier levier n'est pas un code plus rapide, mais moins de code.
Mesurer d'abord, ne jamais deviner

Mesurez avant de toucher quoi que ce soit. Ouvrez le panneau Performance, enregistrez un chargement de page avec un ralentissement du processeur à 4x, et lisez la vue Bottom-Up groupée par URL. Elle attribue les millisecondes aux fichiers. Une supposition sur la dépendance coûteuse est assez souvent fausse pour faire perdre une journée.
Envoyer moins, avant tout le reste
Premier geste : envoyer moins. L'onglet Coverage des DevTools de Chrome montre quel pourcentage de chaque fichier n'a jamais été exécuté. Des chiffres au-dessus de 70 % de code inutilisé sont courants, et ils désignent généralement une bibliothèque importée pour une seule fonction, un paquet de polyfills pour des navigateurs que vous ne prenez plus en charge, ou une bibliothèque entière de dates ou d'icônes là où trois imports suffisaient.
- Enregistrer avec un ralentissement CPU 4x et lire la vue Bottom-Up par URL avant de changer quoi que ce soit
- Onglet Coverage : les fichiers à plus de 70 % inutilisés sont les premiers candidats au retrait
- Remplacer une bibliothèque par une fonction native du navigateur quand elle existe, Intl avant une bibliothèque de dates
- defer pour les scripts qui touchent au DOM, balises tierces chargées après l'événement load
- Découper par route seulement après avoir retiré ce qui ne devrait pas être envoyé du tout
Le remplacement est rarement spectaculaire. Une bibliothèque de formatage de dates qui pèse 70 Ko peut souvent être remplacée par `Intl.DateTimeFormat`, qui ne coûte rien puisqu'il est déjà dans le navigateur. Cette seule substitution supprime en une fois l'analyse, la compilation et l'évaluation, au lieu de les accélérer.
Différer ce dont le premier rendu n'a pas besoin
Deuxième geste : différer ce qui n'est pas nécessaire au premier rendu. Les outils d'analyse d'audience, les widgets de discussion, les bandeaux de consentement et les bibliothèques de carrousel s'exécutent tous avant que la page soit utilisable sans rien y apporter. `defer` sur une balise script garde le téléchargement en parallèle et repousse l'exécution après l'analyse du HTML ; `async` l'exécute dès son arrivée, ce qui est pire pour tout ce qui touche au DOM.
Pour les balises tierces en particulier, les charger après l'événement load, ou à la première interaction, sort tout leur coût de la fenêtre qui est mesurée et, surtout, de la fenêtre pendant laquelle l'utilisateur attend.
Découper le bundle, et dans cet ordre
Troisième geste : découper le bundle. Le découpage du code par route signifie qu'un visiteur de la page d'accueil n'analyse pas le tunnel de paiement. Dans une application Vue, `defineAsyncComponent` et l'`import()` dynamique s'en chargent, et les bundlers modernes découpent automatiquement par route quand les routes sont importées à la demande.
L'ordre de ces trois gestes compte. Découper un bundle qui contient 200 Ko de bibliothèque inutilisée ne fait que repousser le moment où vous la payez. Retirer d'abord la bibliothèque rend le découpage plus petit et le gain plus grand.
Ce que le chiffre ne dit pas
Une mise en garde sur le chiffre lui-même. Le Total Blocking Time et l'Interaction to Next Paint sont ce que vit le visiteur ; le temps d'exécution JavaScript en est une composante, pas un synonyme. Réduire le temps d'exécution sur une page déjà rapide ne change rien de perceptible, et une page peut obtenir un mauvais score d'exécution tout en paraissant fluide, parce que le travail se fait après le rendu.
Les données de terrain tranchent. Une mesure en laboratoire sur un portable rapide masque précisément la population qui souffre : des téléphones Android de milieu de gamme sur un réseau encombré, où une analyse de 300 millisecondes devient deux secondes. Si les chiffres de terrain sont bons et ceux du laboratoire mauvais, croyez le terrain.
Avant d'optimiser les scripts, il vaut la peine de vérifier que les octets sont compressés tout court : gzip vs Brotli, et ce que nous avons trouvé en mesurant 336 organismes publics.
FAQ
Qu'est-ce qui cause un temps d'exécution JavaScript élevé ?
Le volume de JavaScript que le navigateur doit analyser, compiler et évaluer, dominé dans la plupart des projets par les dépendances plutôt que par le code de l'application. Les tâches longues sur le thread principal au démarrage, en général l'initialisation du framework et les balises tierces, sont ce qui transforme ce volume en un chiffre que l'utilisateur ressent.
Le temps d'exécution est-il la même chose que le Total Blocking Time ?
Non. Le temps d'exécution est la durée pendant laquelle les scripts tournent ; le Total Blocking Time mesure combien de temps le thread principal a été bloqué plus de 50 millisecondes d'affilée entre le First Contentful Paint et l'interactivité. Le temps d'exécution en est une composante, et du travail fait après le rendu peut ajouter du temps d'exécution sans ajouter de temps de blocage.
defer ou async réduisent-ils le temps d'exécution ?
Aucun des deux ne réduit le travail ; tous deux déplacent le moment où il a lieu. defer exécute le script après l'analyse du HTML, dans l'ordre du document, ce qui laisse le rendu se faire et constitue le bon choix par défaut pour tout ce qui touche au DOM. async l'exécute dès qu'il est téléchargé, dans un ordre imprévisible.
Combien de JavaScript, c'est trop ?
Il n'existe pas de seuil universel, et tout chiffre présenté comme tel est une règle empirique. Le test utile, ce sont les données de terrain : si l'Interaction to Next Paint et le Largest Contentful Paint restent dans leurs seuils pour de vrais utilisateurs sur de vrais appareils, la quantité envoyée se défend, quel que soit le nombre d'octets.
Faut-il abandonner mon framework pour corriger cela ?
Rarement, et pas en premier. Retirer les dépendances inutilisées, différer les balises tierces et découper par route récupère en général plus de temps qu'une migration de framework, pour une fraction du risque. N'envisagez la migration que si la mesure désigne l'initialisation du framework elle-même après ces trois gestes.



L'ordre de ces trois gestes compte. Découper un bundle qui contient 200 Ko de bibliothèque inutilisée ne fait que repousser le moment où vous la payez. Retirer d'abord la bibliothèque rend le découpage plus petit et le gain plus grand.