Plongez au cœur du moteur JavaScript, comprenez la pile d'exécution, le tas mémoire et le cycle d'événements.
COMPRENDRE LE FONCTIONNEMENT DE JAVASCRIPT
Version Ultra-Détaillée
🏗️ 1. COMMENT LE NAVIGATEUR EXÉCUTE JAVASCRIPT
1.1 Le Processus Complet
┌─────────────────────────────────────────────────────────────────┐
│ PROCESSUS D'EXÉCUTION JS │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌───────────────────┐ │
│ │ TÉLÉCHARGEMENT │ → │ PARSING │ → │ COMPILATION JIT │ │
│ │ (HTML/CSS/JS) │ │ (AST) │ │ (Bytecode) │ │
│ └─────────────┘ └─────────────┘ └───────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ EXÉCUTION │ │
│ │ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ CALL STACK │ │ HEAP MEMORY │ │ │
│ │ │ (Exécution) │ │ (Stockage) │ │ │
│ │ └──────────────┘ └──────────────┘ │ │
│ │ │ │
│ │ ┌──────────────────────────────────────────────────┐ │ │
│ │ │ EVENT LOOP │ │ │
│ │ │ Callback Queue → Call Stack (quand vide) │ │ │
│ │ └──────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ GARBAGE COLLECTOR │ │
│ │ (Nettoyage mémoire) │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
| Étape | Description | Composant |
|---|---|---|
| 1. Téléchargement | Le navigateur télécharge le fichier JS | Réseau |
| 2. Parsing | Analyse syntaxique du code | Parser |
| 3. AST | Conversion en Arbre Syntaxique Abstrait | Parser |
| 4. Compilation JIT | Compilation du bytecode ou code machine | Moteur JS |
| 5. Exécution | Exécution du code sur la Call Stack | Moteur JS |
| 6. Event Loop | Gestion des opérations asynchrones | Moteur JS |
| 7. GC | Nettoyage de la mémoire | Garbage Collector |
🔍 2. PARSING (ANALYSE SYNTAXIQUE)
2.1 Qu'est-ce que le Parsing ?
┌─────────────────────────────────────────────────────────────────┐
│ PROCESSUS DE PARSING │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 1. SCANNEUR (Lexical Analysis) │ │
│ │ Code source → Tokens │ │
│ │ let x = 10; → [LET, IDENTIFIER, EQUALS, NUMBER, ;] │ │
│ └────────────────┬────────────────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 2. PARSEUR (Syntactic Analysis) │ │
│ │ Tokens → AST (Abstract Syntax Tree) │ │
│ └────────────────┬────────────────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 3. COMPILATION (Bytecode Generation) │ │
│ │ AST → Bytecode (pour l'interpréteur) │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Le Scanneur (Lexical Analysis)
// Code source
let
message = "Bonjour";// Tokens générés
[
{ type: 'KEYWORD', value: 'let' },
{ type: 'IDENTIFIER', value: 'message' },
{ type: 'OPERATOR', value: '=' },
{ type: 'STRING', value: '"Bonjour"' },
{ type: 'PUNCTUATOR', value: ';' }
]
🗑️ 6. GARBAGE COLLECTOR (GC)
6.1 Qu'est-ce que le Garbage Collector ?
// Création d'objets
let
obj1 = { name: 'Alice' };let
obj2 = { name: 'Bob' };let
obj3 = { name: 'Charlie' };// L'objet 'Alice' n'est plus référencé
obj1
= null;// Le GC va supprimer { name: 'Alice' } de la mémoire
6.2 Le Cycle de Vie de la Mémoire
┌─────────────────────────────────────────────────────────────────┐
│ CYCLE DE VIE D'UN OBJET │
│ │
│ 1. ALLOCATION │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ let obj = { name: 'Jean' }; │ │
│ │ La mémoire est réservée pour l'objet │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ▼ │
│ 2. UTILISATION │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ console.log(obj.name); │ │
│ │ L'objet est utilisé │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ▼ │
│ 3. LIBÉRATION (GC) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ obj = null; │ │
│ │ // Plus de références │ │
│ │ // GC libère la mémoire │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
6.3 Les Algorithmes de GC
Mark-and-Sweep (Marquage puis Balayage)
Generational Garbage Collection
┌─────────────────────────────────────────────────────────────────┐
│ GÉNÉRATIONS DE V8 (Orinoco) │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ YOUNG GENERATION (Jeune) │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ NEW SPACE │ → │ OLD SPACE │ Objets survécus │ │
│ │ │ (1-2 MB) │ │ (1-2 MB) │ → Promus en Old │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ • GC fréquent (Minor GC) │ │
│ │ • Rapide (quelques ms) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ OLD GENERATION (Vieux) │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ OLD SPACE (100-500 MB) │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ • GC moins fréquent (Major GC) │ │
│ │ • Plus lent (plusieurs dizaines de ms) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ LARGE OBJECT SPACE │ │
│ │ Objets de plus de 1 MB (tableaux, buffers) │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
🧵 7. SINGLE THREAD & EVENT LOOP
7.2 L'Event Loop
Le Cycle Complet
┌─────────────────────────────────────────────────────────────────┐
│ EVENT LOOP - CYCLE COMPLET │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ TIMERS │ │
│ │ Vérifie les setTimeout, setInterval │ │
│ │ Exécute les callbacks prêts │ │
│ └────────────────┬────────────────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ PENDING I/O │ │
│ │ Exécute les callbacks d'erreurs système │ │
│ └────────────────┬────────────────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ IDLE / PREPARE │ │
│ │ Usage interne (libuv) │ │
│ └────────────────┬────────────────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ POLL │ │
│ │ • Attend les nouveaux événements I/O │ │
│ │ • Exécute les callbacks I/O prêts │ │
│ │ • Peut bloquer (se mettre en pause) │ │
│ └────────────────┬────────────────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ CHECK │ │
│ │ Exécute les setImmediate │ │
│ └────────────────┬────────────────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ CLOSE CALLBACKS │ │
│ │ Fermeture des sockets, handles │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 🔄 La boucle recommence ! │
└─────────────────────────────────────────────────────────────────┘
L'Event Loop en Détail
// Pseudo-code de l'Event Loop
while
(true) { // 1. Exécuter toutes les microtasks processMicrotasks(); // 2. Vérifier si la Call Stack est vide while (!callStack.isEmpty()) { callStack.executeNext(); } // 3. Prendre le prochain callback de la queue const callback = callbackQueue.dequeue(); if (callback) { callStack.push(callback); continue; } // 4. Si rien à faire, mettre en pause if (!hasTimers()) { waitForEvents(); } }Exemple Concret
console.log('1. Début');
setTimeout
(() => { console.log('2. Timer (1000ms)'); }, 1000);setTimeout
(() => { console.log('3. Timer (0ms)'); }, 0);Promise.resolve() .then(() => console.log('4. Promise'));
console.log('5. Fin');
// Résultat :
// 1. Début
// 5. Fin
// 4. Promise
// 3. Timer (0ms)
// 2. Timer (1000ms)
7.3 La Call Stack
function
first() { console.log('first'); second(); }function
second() { console.log('second'); third(); }function
third() { console.log('third'); }first();
// Call Stack :
// ═══════════════════════════════════════════════
// 1. [first()] ← Empilé
// 2. [first(), second()] ← Empilé
// 3. [first(), second(), third()] ← Empilé
// 4. [first(), second()] ← Dépilé
// 5. [first()] ← Dépilé
// 6. [] ← Vide
📊 RÉSUMÉ - PHASE 2.2
┌─────────────────────────────────────────────────────────────────┐
│ CYCLE DE VIE DU CODE JS │
│ │
│ Code Source │
│ ↓ │
│ Parsing (Scanning → Tokens) │
│ ↓ │
│ AST (Abstract Syntax Tree) │
│ ↓ │
│ Bytecode (Interprète comme Ignition) │
│ ↓ │
│ Exécution (Call Stack) │
│ ↓ │
│ Profilage (Fonctions "chaudes") │
│ ↓ │
│ JIT (Compilation → Code Machine) │
│ ↓ │
│ Exécution Optimisée │
│ ↓ │
│ Garbage Collector (Nettoyage mémoire) │
└─────────────────────────────────────────────────────────────────┘
| Concept | Définition | Rôle |
|---|---|---|
| Parsing | Analyse du code source | Tokens → AST |
| AST | Arbre syntaxique | Représentation structurelle |
| Bytecode | Instructions compactes | Exécution par l'interpréteur |
| JIT | Compilation Just-In-Time | Optimisation en code machine |
| GC | Garbage Collector | Libération mémoire |
| Event Loop | Boucle d'événements | Gestion asynchrone |
| Call Stack | Pile d'exécution | Suivi des appels |
| Heap | Tasse mémoire | Stockage des objets |