Qu’est-ce que l’Event Loop ?
L’Event Loop est le mécanisme qui permet à JavaScript (single-threaded) d’exécuter du code asynchrone.
Il surveille le Call Stack et les Task Queues, exécutant les tâches dans l’ordre :
Algorithme :
1. Exécuter le code synchrone (Call Stack)
2. Quand le Call Stack est vide :
a. Exécuter TOUTES les Microtasks
b. Exécuter UNE Macrotask
c. Répéter
Analogie du Restaurant :
- Chef (Call Stack) : cuisine une commande à la fois
- Serveur (Event Loop) : apporte les plats quand le chef est disponible
- Commandes VIP (Microtasks) : servies en premier
- Commandes normales (Macrotasks) : servies après les VIP
Quel est le mnémonique pour l’Event Loop ?
R.E.S.T.O (Le Restaurant)
Qu’est-ce que la Call Stack ?
La Call Stack (Pile d’Exécution) est une structure LIFO (Last In, First Out) qui garde trace des fonctions en cours d’exécution.
Exemple :
function third() {
console.log('3');
}
function second() {
third();
}
function first() {
second();
}
first();Call Stack :
│ third() │ ← Exécute et pop │ second() │ ← Appelle third │ first() │ ← Appelle second │ main │ ← Appelle first └──────────┘
Différence entre Microtasks et Macrotasks ?
Microtasks :
- Priorité HAUTE
- TOUTES exécutées avant la prochaine macrotask
- Exemples : Promise.then, queueMicrotask, MutationObserver
Macrotasks :
- Priorité BASSE
- UNE SEULE par cycle d’Event Loop
- Exemples : setTimeout, setInterval, I/O, UI rendering
Tableau :
| Aspect | Microtasks | Macrotasks |
|——–|————|————|
| Priorité | ✅ Haute | ⬇️ Basse |
| Exécution | Toutes | Une seule |
| Bloquant | Oui (si trop) | Non |
Donnez 3 exemples de Microtasks
Promise.resolve().then(() => {});queueMicrotask(() => {});const observer = new MutationObserver(() => {});process.nextTick(() => {});Donnez 3 exemples de Macrotasks
setTimeout(() => {}, 0);
setInterval(() => {}, 100);setImmediate(() => {});Quel est l’ordre d’exécution ?
console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
queueMicrotask(() => console.log('D'));
console.log('E');Résultat : A, E, C, D, B
Explication détaillée :
setTimeout : Enregistré dans Macrotask QueuePromise.then : Enregistré dans Microtask QueuequeueMicrotask : Enregistré dans Microtask QueueOrdre Event Loop :
Synchrone → Toutes Microtasks → Une Macrotask
Pourquoi ce code peut bloquer ?
function loop() {
Promise.resolve().then(loop);
}
loop();
setTimeout(() => console.log('Timeout'), 0);Résultat : ‘Timeout’ ne s’exécute JAMAIS !
Pourquoi ?
La fonction loop() ajoute constamment de nouvelles microtasks.
L’Event Loop exécute TOUTES les microtasks avant les macrotasks.
Si on ajoute constamment des microtasks, les macrotasks ne sont jamais traitées.
C’est le ‘microtask starvation’.
Visualisation :
loop() → Promise.then(loop) → loop() → Promise.then(loop) → ...
↑\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_|
Les microtasks ne finissent jamais
→ setTimeout n'est jamais exécutéQuel est l’ordre de priorité de l’Event Loop ?
Ordre de priorité (du plus haut au plus bas) :
1. Call Stack (Code synchrone) ↓ 2. Microtasks (TOUTES) - Promise.then/catch/finally - queueMicrotask() - MutationObserver ↓ 3. Macrotask (UNE SEULE) - setTimeout - setInterval - I/O ↓ 4. Retour à l'étape 2 (Event Loop)
Règle : Synchrone > Toutes Microtasks > Une Macrotask
Ordre d’exécution dans Node.js avec process.nextTick ?
Dans Node.js, process.nextTick a la plus haute priorité :
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
process.nextTick(() => console.log('4'));
console.log('5');Résultat : 1, 5, 4, 3, 2
Ordre Node.js :
1. Code synchrone (1, 5)
2. process.nextTick (4)
3. Microtasks/Promises (3)
4. Macrotasks/setTimeout (2)
Que se passe-t-il si on ajoute des microtasks dans une microtask ?
Les nouvelles microtasks sont ajoutées à la queue et seront exécutées avant la prochaine macrotask.
Exemple :
Promise.resolve()
.then(() => {
console.log('1');
Promise.resolve().then(() => console.log('2'));
})
.then(() => console.log('3'));
setTimeout(() => console.log('4'), 0);Résultat : 1, 2, 3, 4
Explication :
1. Première microtask : ‘1’ + ajoute nouvelle microtask
2. Deuxième microtask : ‘2’
3. Troisième microtask : ‘3’
4. Toutes microtasks terminées → Macrotask : ‘4’
Comment débugger l’Event Loop ?
1. Console.log avec timestamp :
function log(msg) {
console.log(`[${performance.now().toFixed(2)}ms] ${msg}`);
}
log('Start');
setTimeout(() => log('Timeout'), 0);
Promise.resolve().then(() => log('Promise'));
log('End');2. Chrome DevTools - Performance Tab :
- Ouvrir DevTools
- Onglet Performance
- Enregistrer
- Voir les Tasks, Microtasks, etc.
3. Visualiser la queue :
console.log('Call Stack:', 'Message');
queueMicrotask(() => console.log('Microtask:', 'Message'));
setTimeout(() => console.log('Macrotask:', 'Message'), 0);