Créa-blog

#100JoursPourCoder
Projet Créa-code

Ressources pour développeur web

Théme de la semaine : MySQL

Defer et Async : maîtrisez le chargement HTML et JavaScript

Temps de lecture estimé : 9 minutes
Accueil HTML5 Defer et Async : maîtrisez le chargement HTML et JavaScript

Lorsque l’on débute en développement web, on découvre très vite qu’un site n’est pas seulement une page HTML figée. Il y a aussi des feuilles de style, des images… et surtout du JavaScript. Ce dernier permet d’ajouter des interactions, d’animer des éléments, de vérifier des formulaires, bref, de rendre un site vivant. Mais une question se pose vite : comment faire en sorte que le JavaScript se charge au bon moment, et sans ralentir l’affichage de la page ? C’est là qu’interviennent defer et async.

  • Comprendre comment charger vos scripts JavaScript sans bloquer l’affichage et améliorer la vitesse de votre page.
  • Savoir choisir entre defer et async pour éviter les erreurs liées à l’ordre d’exécution ou au DOM non prêt.
  • Adopter les bonnes pratiques modernes afin de rendre votre site plus fluide, fiable et agréable à utiliser.

Sans explication, le sujet defer et async peut sembler un peu flou. Pourtant, comprendre ces deux attributs est essentiel pour optimiser vos pages web. C’est un peu comme organiser un spectacle : si un accessoire important arrive trop tard, tout le monde attend. Et si un acteur débarque trop tôt, il risque de perturber les répétitions.

Vous allez découvrir que defer et async sont finalement très logiques. Ils vous permettent de contrôler précisément le chargement de vos scripts JavaScript pour gagner en rapidité et en performance. Et vous verrez que ce n’est pas réservé aux experts.

Pourquoi le chargement JavaScript peut ralentir votre page

Pour bien comprendre l’intérêt de async et defer, il faut d’abord savoir ce qui se passe lorsqu’un navigateur lit votre page HTML.

Imaginez que le navigateur avance dans le code ligne par ligne, tel un lecteur sérieux qui ne saute pas un mot. Quand il tombe sur une balise <script> classique comme celle-ci :

<script src="app.js"></script>

il s’arrête. Il met le HTML en pause. Il télécharge le script. Puis il l’exécute. Et seulement ensuite, il reprend la lecture de votre page.

Cela signifie qu’un script placé en haut de votre document peut empêcher le contenu d’apparaître rapidement à l’écran. Sur une connexion lente, on a parfois l’impression que la page est vide et que rien ne se passe. Ce n’est pas une bonne expérience pour l’utilisateur.

Sans aucune optimisation, JavaScript peut donc devenir un bouchon sur l’autoroute de l’affichage.

La méthode classique : placer les scripts avant la fermeture du body

Pendant longtemps, pour éviter de bloquer l’affichage, on conseillait de mettre les scripts tout à la fin du HTML, juste avant la balise </body>.

<body>
  <h1>Bonjour</h1>
  <p>Bienvenue sur ma page</p>

  <script src="app.js"></script>
</body>

Résultat : tout le contenu s’affiche d’abord, puis le JavaScript se charge. Le visiteur n’attend plus dans le noir.

Cette méthode fonctionne encore, mais elle a des limites. Si le JavaScript est indispensable au fonctionnement de certains éléments de la page, il peut arriver trop tard. Par exemple, si un script doit générer une partie du contenu, celui-ci ne s’affichera qu’après téléchargement.

Pour aller plus loin, HTML5 a introduit deux attributs qui rendent le chargement plus intelligent : async et defer.

Async : votre script se télécharge sans attendre les autres

L’attribut async permet de charger un script en parallèle du HTML. Le navigateur ne bloque plus l’affichage lorsqu’il rencontre ce script. Et dès que le script est téléchargé, il s’exécute immédiatement, même si le HTML n’est pas encore entièrement chargé.

Exemple :

<script src="app.js" async></script>

C’est un peu comme si vous aviez un livre en main, mais que vous demandiez à un ami d’aller chercher les illustrations ailleurs. Il vous les apporte dès qu’il les trouve, et vous les ajoutez dans votre lecture même si vous n’avez pas encore fini le chapitre.

C’est très rapide. Le problème ? Un script async n’attend personne, et personne ne l’attend. Si vous avez plusieurs scripts async, leur ordre d’exécution peut changer selon le réseau ou le serveur.

Ce qu’il faut retenir d’async

Un script async :

  • ne bloque pas le rendu HTML,
  • s’exécute dès qu’il est téléchargé,
  • peut s’exécuter dans un ordre imprévisible.

C’est donc parfait pour les scripts qui n’ont pas besoin d’attendre que le reste de la page soit analysé. Par exemple : Google Analytics, un tracker publicitaire, une fonctionnalité non essentielle.

Defer : la stratégie zen du chargement JavaScript

L’attribut defer, lui aussi, permet de charger un script en parallèle du HTML. Mais il y a une énorme différence avec async : le script ne s’exécute qu’une fois le HTML entièrement chargé et analysé.

Exemple :

<script src="main.js" defer></script>

Le navigateur télécharge le fichier dès qu’il l’aperçoit, mais il dit au script : « Patience… tu joueras quand tout le monde sera prêt ».

C’est idéal si votre JavaScript manipule des éléments de la page (DOM). Avec defer, vous êtes certain que ce DOM est disponible.

Ce qu’il faut retenir de defer

Un script defer :

  • ne bloque pas le rendu HTML,
  • s’exécute après le chargement complet du HTML,
  • respecte l’ordre d’apparition dans le code.

C’est la solution idéale pour la majorité des scripts modernes, surtout ceux qui interagissent avec les éléments de la page.

Il peut arriver qu’un script essaye de modifier un bouton qui n’existe pas encore. Résultat : une belle erreur dans la console, et une page qui refuse d’obéir. Avec defer, ce genre de mésaventure n’arrive plus.

Async vs Defer : un duel rapide pour bien choisir

Prenons une petite histoire. Async, c’est le sprinteur impatient. Il veut partir dès qu’il est prêt. Même si ses amis ne le suivent pas. Defer, c’est le sportif discipliné. Il se chauffe en douce, mais n’exécute son numéro qu’une fois que chacun est en place.

Voici comment le navigateur se comporte :

AttributTéléchargement du scriptExécution
asyncEn parallèle du HTMLDès que prêt
deferEn parallèle du HTMLAprès HTML complet

Si votre JavaScript dépend du contenu HTML, alors defer est votre meilleur allié.

Si votre script n’a aucune dépendance et aucune importance pour l’affichage, alors async permet d’accélérer au maximum.

Plusieurs scripts sur une même page : attention à l’ordre

Pour bien comprendre la différence entre async et defer, prenons deux scripts qui dépendent l’un de l’autre. Par exemple, une librairie puis votre fichier personnel :

<script src="librairie.js"></script>
<script src="main.js"></script>

Dans cette version classique, l’ordre est garanti. La librairie sera forcément chargée et exécutée avant votre script principal.

Mais en ajoutant async, cet ordre peut se briser :

<script src="librairie.js" async></script>
<script src="main.js" async></script>

Chaque fichier part dans sa propre compétition au téléchargement. Celui qui finit premier s’exécute… même si ce n’était pas celui qui devait initialiser les fonctions.

Résultat, des erreurs étranges parce que votre script utilise des fonctions qui ne sont pas encore disponibles.

Avec defer au contraire, l’ordre visuel dans votre HTML est toujours respecté :

<script src="librairie.js" defer></script>
<script src="main.js" defer></script>

Même s’ils se téléchargent en même temps, le navigateur attend la fin de l’analyse du HTML et exécutera librairie.js puis main.js, dans cet ordre précis.

C’est l’un des gros points forts de defer.

Comment le navigateur charge une page avec Defer et Async

Pour vous aider à bien visualiser, voici trois scénarios fréquents.

1) Script sans attribut

Le navigateur :

  • s’arrête pour télécharger le script,
  • puis l’exécute,
  • puis continue le HTML.

Le rendu est bloqué.

2) Script avec async

Le navigateur :

  • télécharge le script en parallèle,
  • continue d’analyser la page,
  • exécute le script dès qu’il est prêt.

L’affichage n’est pas bloqué, mais l’ordre n’est plus assuré.

3) Script avec defer

Le navigateur :

  • télécharge le script en parallèle,
  • continue d’analyser la page,
  • exécute tous les scripts defer dans l’ordre,
  • juste avant l’événement DOMContentLoaded.

Tout le monde est content : rapide et structuré.

Une manière simple de se souvenir :

  • Async → « dès que possible »
  • Defer → « au bon moment »

Exemple concret : un bouton qui ne s’affiche pas correctement

Voici un petit scénario qu’un débutant rencontre souvent : vous faites un script qui doit ajouter une classe ou afficher un texte dans un élément HTML. Mais le script est placé dans le <head>. Le navigateur lit <script>, tente d’exécuter le code, mais le bouton n’existe pas encore dans le DOM.

Avec un script classique placé dans le head :

<head>
  <script src="bouton.js"></script>
</head>
<body>
  <button id="action">Cliquez-moi</button>
</body>

Dans votre fichier bouton.js :

Formation web et informatique - Alban Guillier - Formateur

Des formations informatique pour tous !

Débutant ou curieux ? Apprenez le développement web, le référencement, le webmarketing, la bureautique, à maîtriser vos appareils Apple et bien plus encore…

Formateur indépendant, professionnel du web depuis 2006, je vous accompagne pas à pas et en cours particulier, que vous soyez débutant ou que vous souhaitiez progresser. En visio, à votre rythme, et toujours avec pédagogie.

Découvrez mes formations Qui suis-je ?
document.getElementById('action').textContent = 'Go !';

Résultat : erreur dans la console, votre bouton ne change pas.

Avec defer, tout fonctionne :

<head>
  <script src="bouton.js" defer></script>
</head>

Votre script attend que toute la structure HTML soit prête avant de se lancer. Il n’arrive plus en avance.

Où placer les scripts : head ou body ?

Aujourd’hui, la réponse la plus moderne est presque toujours la même :
Placer vos scripts dans le <head> avec l’attribut defer.

<head>
  <script src="main.js" defer></script>
</head>

Ce placement présente deux grands avantages :

  • Les scripts ne bloquent pas l’affichage de la page
  • Ils s’exécuteront exactement au bon moment

Async, lui, peut être placé soit en <head>, soit en <body>. Mais on le réserve essentiellement à des scripts qui n’interagissent pas avec le DOM.

Quand utilise-t-on async en pratique ?

Même si defer semble parfait, async a aussi sa place.

Vous utiliserez async pour des scripts :

  • externes,
  • qui ne dépendent de rien,
  • et dont l’ordre n’a pas d’importance.

Quelques exemples courants :

  • Google Analytics
  • Outils de statistiques
  • Scripts publicitaires
  • Widgets tiers non essentiels

Exemple classique :

<script async src="https://www.googletagmanager.com/gtag/js?id=UA-XXXX"></script>

Le suivi des visiteurs n’a pas besoin d’arriver en dernier ou en premier. Il doit juste être chargé quand l’utilisateur est là. Async est donc parfait ici.

Interaction avec l’événement DOMContentLoaded

En JavaScript, il existe un événement que vous rencontrerez souvent :

document.addEventListener('DOMContentLoaded', () => {
  console.log('DOM prêt !');
});

Cet événement est déclenché quand le HTML est totalement chargé et analysé.

Un script marqué defer s’exécutera juste avant que DOMContentLoaded soit déclenché. C’est idéal si vous comptez manipuler la structure HTML à ce moment précis.

Un script async, lui, peut s’exécuter avant, après ou au milieu… Il ne se soucie pas de DOMContentLoaded. Voilà pourquoi il faut être prudent.

Le cas particulier du script Inline

Si vous écrivez du JavaScript directement dans votre fichier HTML, sans fichier externe :

<script>
  console.log("Bonjour !");
</script>

Les attributs async et defer ne sont pas pris en compte. Le navigateur exécute immédiatement ce qu’il trouve. D’où l’intérêt d’externaliser votre code dès que possible, surtout pour des projets sérieux.

Comment vérifier si async et defer fonctionnent bien

Les navigateurs proposent des outils indispensables pour analyser le temps de chargement.

Dans Google Chrome, avec Chrome DevTools, par exemple :

  • clic droit,
  • Inspecter,
  • onglet Réseau (Network)

Rechargez la page et observez :

  • le moment où les scripts sont téléchargés
  • le moment où ils sont exécutés
  • l’impact sur l’affichage

Vous verrez rapidement que defer rend la page lisible beaucoup plus vite.

Il existe aussi l’onglet Performances pour aller encore plus loin, mais pour débuter, le panneau Réseau est déjà très instructif.

Les modules ES6 : un comportement spécial à connaître

Depuis l’arrivée des modules JavaScript modernes, le comportement des scripts a légèrement évolué. Lorsque vous utilisez l’attribut type="module", le navigateur applique automatiquement un fonctionnement proche de defer.

Exemple :

<script type="module" src="app.js"></script>

Ce script se télécharge sans bloquer le HTML et s’exécute après que la page soit prête. Vous n’avez même pas besoin de rajouter defer.

Cependant, une différence importante subsiste : les modules sont exécutés en mode strict par défaut, ce qui évite certaines erreurs silencieuses. Ils permettent aussi d’importer d’autres fichiers JavaScript facilement :

import { sayHello } from './utils.js';
sayHello();

Si vous débutez, vous ne croiserez pas forcément les modules dès demain, mais c’est une bonne idée de savoir que l’avenir du JavaScript se dirige clairement dans cette direction.

Scripts dynamiques ajoutés par JavaScript

Certains scripts ne sont pas écrits directement dans le HTML, mais ajoutés par JavaScript. Par exemple :

const script = document.createElement('script');
script.src = 'pub.js';
document.body.appendChild(script);

Dans ce cas, le comportement se rapproche davantage d’un script async, car le navigateur lancera l’exécution dès que le fichier est disponible.

Si vous avez vraiment besoin de garantir un ordre d’exécution entre scripts dynamiques, il faut utiliser des techniques plus avancées, comme attendre l’événement load sur la balise script, ou utiliser les promesses.

Les erreurs fréquentes de débutants

Lorsque l’on découvre defer et async, plusieurs pièges reviennent souvent.

On pense parfois qu’il faut mettre async partout. C’est faux : son ordre imprévisible peut casser votre page.

On peut aussi oublier que defer ne marche pas sur des scripts inline, ce qui peut provoquer de petites frayeurs lorsque l’on imagine qu’un script dans le head s’exécutera plus tard.

Autre erreur classique : mélanger async et defer dans un même groupe de scripts qui dépendent les uns des autres. Cela crée un mélange incontrôlable.

Si vous retenez une règle simple : les scripts qui interagissent avec la page doivent être en defer, vous éviterez déjà 90 % des problèmes.

Bonne pratique moderne : tout en defer dans le head

Pour un site bien optimisé aujourd’hui, la solution la plus efficace ressemble vraiment à :

<head>
  <script src="librairie.js" defer></script>
  <script src="main.js" defer></script>
</head>

Vous profitez de tous les avantages :

  • un chargement rapide,
  • un affichage sans attente,
  • un ordre respecté,
  • un JavaScript prêt au bon moment.

Async devient un bonus, que l’on sort de sa poche uniquement pour les scripts indépendants, souvent externes.

Petit exercice pour vous entraîner

Imaginons trois scripts :

  • Un script qui affiche un message dans la console
  • Une librairie qui contient des fonctions utilisées par les deux autres scripts
  • Un script qui utilise cette librairie pour modifier la page

Comment les chargeriez-vous ?

Si vous avez pensé à :

  • mettre la librairie en premier,
  • puis les deux autres,
  • tous avec defer,

vous avez tout compris.

Tout développeur a connu ce moment où l’on recharge la page… et où l’écran reste tristement blanc. Après dix, quinze secondes, un contenu apparaît enfin. Le réflexe du débutant est de penser que le serveur est lent. Souvent, la vraie raison est plus simple : un énorme script placé en haut du HTML a bloqué le rendu.


Maîtriser defer et async, c’est un peu comme apprendre à bien gérer le timing d’un spectacle. Tous les acteurs sont présents, mais pour que la représentation soit fluide, chacun doit entrer en scène au bon moment. Grâce à ces deux attributs, votre JavaScript devient plus rapide, plus fiable, et votre page n’a plus cette hésitation gênante avant de s’afficher.

Aujourd’hui, la pratique la plus saine consiste à utiliser defer pour la grande majorité de vos scripts. Cela vous permet de garder le contrôle, de préserver l’ordre d’exécution, et de garantir que le DOM est prêt lorsque vous en avez besoin. Async reste utile, mais à petites doses, uniquement lorsque l’ordre n’a aucune importance et que la rapidité est la priorité.

Si vous continuez à explorer le web, vous croiserez de plus en plus de situations où le chargement intelligent du JavaScript fera toute la différence. Prenez l’habitude de vous demander : « Ce script a-t-il besoin d’attendre la page ? Peut-il se lancer seul ? ». Cette simple réflexion vous fera gagner du temps et améliorera l’expérience de chaque visiteur.

Vous avez désormais les clés pour optimiser le chargement de votre JavaScript et rendre vos pages aussi rapides que confortables. Et si un jour un collègue vous demande de choisir entre async et defer, vous pourrez répondre avec le sourire : « Ça dépend du rôle de l’acteur dans la pièce ».