Avez-vous une question? (216) 97 656 803 hajjriadh@gmail.com
JavaScript

18.2 La boucle d'événements (event loop)

La boucle d'événements (event loop). Dans cette leçon du cours JavaScript, vous apprendrez à : • décrire le rôle de la pile d'appels, des API de l'environnement et des files d'attente ; • expliquer co...

0 chapitres 0 QCM Accès gratuit
Dans cet article

À propos de ce cours

La boucle d'événements (event loop). Dans cette leçon du cours JavaScript, vous apprendrez à : • décrire le rôle de la pile d'appels, des API de l'environnement et des files d'attente ; • expliquer comment la boucle d'événements décide de ce qui s'exécute ; • distinguer microtâches et macrotâches, et prévoir leur ordre ; • comprendre pourquoi un délai de setTimeout est un minimum, pas une garantie.

Chapitre 18 — La programmation asynchrone · Leçon 2 : La boucle d'événements (event loop)

🎯 Objectifs de la leçon
• décrire le rôle de la pile d'appels, des API de l'environnement et des files d'attente ;
• expliquer comment la boucle d'événements décide de ce qui s'exécute ;
• distinguer microtâches et macrotâches, et prévoir leur ordre ;
• comprendre pourquoi un délai de setTimeout est un minimum, pas une garantie.

1. La pile d'appels (call stack)

La pile d'appels mémorise les fonctions en cours d'exécution. Quand une fonction est appelée, elle est empilée; quand elle se termine, elle est dépilée. Comme une pile d'assiettes : la dernière posée est la première retirée.

function trois() {
  console.log("dans trois()");
}
function deux() {
  trois();
  console.log("dans deux()");
}
function un() {
  deux();
  console.log("dans un()");
}

un();

Résultat dans la console

dans trois()
dans deux()
dans un()

un() est empilée, puis deux(), puis trois(). trois() se termine la première, puis deux(), puis un(). Tant que la pile n'est pas vide, rien d'autre ne peut s'exécuter.

2. Les acteurs de l'asynchrone

  • Les API de l'environnement: le navigateur (ou Node.js) gère lui-même les minuteries, les requêtes réseau, les événements. Ce travail ne se fait pas dans la pile de JavaScript.
  • La file des tâches (macrotâches) : quand un timer est écoulé, quand un clic a lieu ou qu'une réponse réseau arrive, le callback correspondant est placé dans cette file.
  • La file des microtâches: elle reçoit les suites des promesses (.then, .catch, la reprise après await) et les fonctions passées à queueMicrotask.
  • La boucle d'événements: elle surveille la pile et, dès qu'elle est vide, y fait entrer le travail en attente.

Schéma de la boucle d'événements avec pile d'appels, API et files d'attente
Figure 2 — Le fonctionnement de la boucle d'événements.

3. L'algorithme de la boucle

  1. Exécuter le code du script jusqu'à ce que la pile soit vide.
  2. Exécuter toutes les microtâches en attente (y compris celles ajoutées pendant ce temps).
  3. Le navigateur peut redessiner la page.
  4. Prendre une seule macrotâche dans la file des tâches et l'exécuter.
  5. Recommencer à l'étape 2.
console.log("A - code du script");

setTimeout(() => console.log("B - setTimeout (macrotâche)"), 0);

Promise.resolve().then(() => console.log("C - then (microtâche)"));

queueMicrotask(() => console.log("D - queueMicrotask (microtâche)"));

console.log("E - code du script");

Résultat dans la console

A - code du script
E - code du script
C - then (microtâche)
D - queueMicrotask (microtâche)
B - setTimeout (macrotâche)

A et E font partie du script : ils passent en premier. Ensuite viennent les microtâches C et D, dans leur ordre d'arrivée. Le callback de setTimeout (B), une macrotâche, ne passe qu'après, même avec 0 ms.

4. Un délai est un minimum

Le callback d'un timer ne peut entrer dans la pile que lorsqu'elle est vide. Si le script la monopolise, le timer attend :

const debut = Date.now();

setTimeout(() => {
  console.log(`Timer exécuté après ${Date.now() - debut} ms (demandé : 100 ms)`);
}, 100);

// La pile reste occupée pendant 1 seconde
while (Date.now() - debut < 1000) {}
console.log("Boucle terminée");

Résultat dans la console (la durée exacte varie d'une exécution à l'autre)

Boucle terminée
Timer exécuté après 1002 ms (demandé : 100 ms)
⚠️ Attention
Une page reste fluide si chaque morceau de code s'exécute vite. Un calcul de plusieurs secondes bloque la boucle : ni les clics, ni l'affichage, ni les timers ne peuvent passer. Pour les vrais calculs lourds, on utilise des Web Workers, qui tournent sur un autre fil.
ℹ️ À retenir
• La pile d'appels exécute une seule fonction à la fois ; elle doit se vider pour que le reste passe.
• Les attentes (timers, réseau, événements) sont gérées par l'environnement, hors de la pile.
• Ordre d'un tour : le code en cours → toutes les microtâches → une macrotâche.
• Promesses = microtâches (prioritaires) ; setTimeout et événements = macrotâches.
• Le délai de setTimeout est un minimum : un code bloquant le retarde.

🛠 Activité 2 — Jouer à la boucle d'événements

Mission : Simulez « à la main » la boucle d'événements, en dessinant à chaque étape le contenu de la pile et des deux files.

Questions pour avancer (répondez dans votre compte rendu, puis appliquez dans votre projet) :

  1. Prévoyez l'affichage de ce programme, puis dessinez l'état de la pile, de la file des microtâches et de la file des tâches après chaque ligne :
    console.log("début");
    setTimeout(() => console.log("timeout 1"), 0);
    Promise.resolve().then(() => {
      console.log("promesse 1");
      setTimeout(() => console.log("timeout 2"), 0);
    });
    Promise.resolve().then(() => console.log("promesse 2"));
    console.log("fin");
  2. Dans l'exemple l2_ordre.js, pourquoi C passe-t-il avant B alors que les deux ont un « délai » nul ?
  3. Une microtâche peut ajouter une autre microtâche. Que se passerait-il si une microtâche en ajoutait une nouvelle à chaque fois, sans fin ? La page pourrait-elle encore se redessiner ?
  4. Ouvrez le site Loupe (visualisation de la boucle d'événements) et collez-y l'exemple l1_async.js. Décrivez en trois phrases ce que vous observez.
  5. Dans une page web, un bouton lance un calcul de 3 secondes au clic. Pendant le calcul, l'utilisateur clique sur un autre bouton. Quand ce second clic est-il traité ? Justifiez avec le vocabulaire de la leçon.

Je vérifie / je rends :

  • ☐ Vos dessins de la question 1.
  • ☐ Les réponses rédigées aux autres questions.

← 18.1 — Code synchrone et asynchrone18.3 — Les callbacks asynchrones et le « callback hell » →