heymath < Blog />

Scripts sync, defer et async : petite subtilité & performance

Publié le

Hey!

Je m’étais fait une fausse idée sur un sujet pourtant basique : les balises <script>. Alors je vous propose un petit rappel des bases et une précision qui peut avoir son importance par rapport aux performances Web.

Scripts synchrones

Vous le savez probablement, les scripts par défaut sont synchrones.

Cela signifie que lors du chargement d’une page, le navigateur va analyser (parse) le document HTML en parcourant les éléments d’haut en bas et de gauche à droite, puis dès qu’il va détecter un script, il va :

  1. mettre en pause l’analyse HTML
  2. télécharger le script
  3. exécuter le script
  4. reprendre l’analyse HTML
<script src="script-synchrone.js"></script>

NB : par défaut, un script sera en revanche asynchrone en JavaScript, il faut donc préciser que le script est synchrone avec un booléen :

const script  = document.createElement('script');
script.async = false;
script.src = 'script-synchrone.js';

Scripts différés

Scripts avec un attribut defer (aussi defer="" ou defer="defer").

La différence avec un script synchrone, c’est que le navigateur lance le téléchargement sans mettre en pause l’analyse du document HTML, ces actions s’effectuent donc en parallèle.

Lorsque l’analyse HTML est terminée et juste avant l’évènement DOMContentLoaded, le navigateur va alors exécuté chaque script defer en respectant leur ordre dans le HTML.

Un script defer situé avant un autre script defer sera donc toujours exécuté en premier et le script suivant sera exécuté lorsque l’exécution du premier sera terminée.

<script src="script-différé.js" defer></script>
<script src="script-différé.js" defer=""></script>
<script src="script-différé.js" defer="defer"></script>

NB : c’est une propriété de type booléen en JavaScript

const script  = document.createElement('script');
script.defer = true;
script.src = 'script-différé.js';

Scripts asynchrones

Script avec un attribut async (aussi async="" ou async="async").

Tout comme un script différé, le navigateur lance le téléchargement du script async sans mettre en pause l’analyse du document HTML.

La différence, c’est que le navigateur va exécuter le script dès que celui-ci sera téléchargé.

<script src="script-asynchrone.js" async></script>
<script src="script-asynchrone.js" async=""></script>
<script src="script-asynchrone.js" async="async"></script>

NB : c’est une propriété de type booléen en JavaScript

const script  = document.createElement('script');
script.async = true;
script.src = 'script-asynchrone.js';

La petite subtilité

Je m’étais toujours dit que les scripts en async étaient donc la “solution ultime” pour les performances web. Car ils s’exécutent dès que possible, ce qui peut paraître un gage de rapidité, mais c’est en réalité un peu plus subtile que ça.

Le téléchargement d’un script async ne bloque pas l’analyse du HTML, en revanche son exécution met en pause l’analyse du document HTML.

Si cette exécution intervient pendant l’analyse du HTML, le script async va retarder la construction du DOM nécessaire au premier affichage de la page.

Il faut donc faire attention de ne pas inclure des scripts async trop “gourmands”.

En résumé

script

  • pour bloquer le chargement de tout ce qui le suit dans le document HTML : tant que le script n’est pas téléchargé, analysé et exécuté (donc sauf cas particulier, ne pas utiliser)

script defer

  • pour charger des scripts sans bloquer l’analyse du HTML ni l’affichage de la page
  • pour charger plusieurs scripts en parallèle, puis les exécuter dans un ordre garanti

script async

  • pour des scripts qui ne sont pas “gourmands”
  • pour charger plusieurs scripts en parallèle, puis les exécuter dans un ordre aléatoire

Sources


Mathieu Dutto / développeur frontend chez Evaneos. Je m’intéresse aux performances web et à la maintenabilité du code. Vous pouvez me retrouver sur Twitter et GitHub.

Mathieu Dutto © 2020, built with Gatsby