L'event loop et la file d'attente
Un fil, une pile, une file : prédire l’ordre d’exécution.
Objectifs
À la fin de cette leçon, vous saurez :
- décrire le rôle de l'event loop ;
- prédire l'ordre d'exécution entre code direct et callbacks ;
- expliquer le résultat du célèbre exemple setTimeout(…, 0).
Un seul fil, une boucle
JavaScript est mono-threadé : un seul fil exécute votre code. L'event loop (boucle d'événements) fait tourner ce fil en permanence :
┌──────────────────────────────┐
│ pile d'exécution │ le code courant
└──────────────────────────────┘
↑ prend le travail quand la pile est vide
┌──────────────────────────────┐
│ file des tâches (queue) │ callbacks prêts à tourner
└──────────────────────────────┘
Règle unique : l'event loop ne sort un callback de la file que lorsque la pile est vide.
Le test classique
setTimeout(function () {
console.log("B");
}, 0);
console.log("A");
// Affichage :
// A
// B
Pourquoi B après A alors que le délai vaut zéro ?
setTimeoutn'exécute pas : il programme — le callback part dans la file.console.log("A")s'exécute immédiatement (pile occupée).- La pile se vide ; l'event loop récupère alors le callback de « B ».
Le 0 signifie « dès que tu auras le temps », pas « tout de suite ». C'est LA démonstration que l'asynchronisme ne crée pas de parallélisme : il réorganise l'ordre dans un seul fil.
Ce qui passe par la file
setTimeout(() => console.log("timer"), 0);
Promise.resolve().then(() => console.log("promise"));
console.log("direct");
// direct
// promise ← micro-tâche : vidée avant les timers
// timer
Nuance utile : les résolutions de Promises forment une file prioritaire (microtasks) traitée avant les timers (macrotasks). Retenez simplement l'ordre : code direct → promesses → timers.
Conséquence pratique : ne jamais bloquer
// À ÉVITER : boucle qui gèle tout pendant 5 secondes
const debut = Date.now();
while (Date.now() - debut < 5000) { /* rien */ }
Pendant cette boucle, aucun callback, aucun clic, rien : la queue attend que la pile libère le fil. Sur un serveur Node, c'est pire encore : TOUS les clients sont gelés. Tout traitement long devra être découpé ou délégué — principe fondateur de l'architecture Node.
Exercice
Prédisez puis vérifiez :
setTimeout(() => console.log(1), 0);
console.log(2);
setTimeout(() => console.log(3), 0);
console.log(4);
Promise.resolve().then(() => console.log("p"));
setTimeout(() => console.log("t"), 0);
console.log("s");
- Expliquez pourquoi
whilebloquant etsetTimeoutrépété produisent des expériences radicalement différentes pour l'utilisateur.
Résumé
- Un fil, une pile, une file : l'event loop redistribue le travail.
- Code direct toujours avant callbacks ; promesses avant timers.
- Bloquer la pile = bloquer le monde entier du programme.
Correction disponibleCherchez d’abord par vous-même.Voir la correction
Correction
Réponses détaillées
Exercice 1. Affiche 2, 4, puis 1, 3. Les deux callbacks patientent en file jusqu'à la fin du script direct.
Exercice 2. Affiche s, p, t : la microtask promise passe avant la macrotask timer.
Question 3. Le while occupe la pile en continu : l'event loop ne peut jamais prendre un callback → interface figée. Les setTimeout successifs libèrent la pile entre chaque tour : l'event loop respire, l'interface continue de répondre.