Scripts sync, defer et async : petite subtilité & performance
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 :
- mettre en pause l’analyse HTML
- télécharger le script
- exécuter le script
- 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