⏰ JavaScript Asynchrone

Maîtriser le code qui ne bloque pas

Callbacks • Promises • Async/Await • Fetch API

Formation DWWM - 2026

Au programme 📋

# ⏱️ Partie 0

Qu'est-ce que l'asynchrone ?

Comprendre le concept fondamental

C'est quoi l'asynchrone ? 🤔

L'asynchrone permet d'exécuter du code sans attendre qu'une opération longue se termine.

Analogie : Le restaurant 🍽️

Restaurant SYNCHRONE (bloquant) :

Le serveur prend la commande du client 1, va en cuisine, attend que le plat soit prêt (30 min), revient, sert, puis va voir le client 2. Pendant ce temps, les autres clients attendent et s'impatientent ! ❌

Restaurant ASYNCHRONE (non-bloquant) :

Le serveur prend la commande du client 1, la transmet en cuisine, et IMMÉDIATEMENT va prendre la commande du client 2, puis du 3, etc. Quand un plat est prêt, le serveur revient le servir. Tout le monde est content ! ✅

L'asynchrone en JavaScript : Ton code peut continuer à s'exécuter pendant qu'une opération longue (requête réseau, lecture de fichier...) est en cours.

Opérations asynchrones courantes ⏳

Certaines opérations prennent du temps et doivent être asynchrones :

Opération Temps Pourquoi c'est long ?
Requête HTTP 100ms - 5s+ Dépend du réseau et du serveur
Lecture de fichier 10ms - 1s+ Dépend de la taille et du disque
Accès base de données 10ms - 2s+ Requêtes complexes, connexion réseau
setTimeout / setInterval Variable Délai intentionnel
Géolocalisation 1s - 5s+ GPS, permissions utilisateur

⚠️ Problème : Si ces opérations étaient SYNCHRONES (bloquantes), toute l'application se figerait pendant l'attente. L'utilisateur ne pourrait rien faire ! La page serait complètement bloquée !

✅ Solution : Les faire en ASYNCHRONE ! Le code continue de s'exécuter, et quand l'opération est terminée, on exécute une fonction de rappel (callback).

Code Synchrone vs Asynchrone 🔄

Code Synchrone (bloquant)

console.log("1. Début");

// Opération longue (bloque tout !)
attendreBloquant(3000);

console.log("2. Fin");

// Résultat :
// 1. Début
// ... attend 3 secondes ...
// 2. Fin

❌ Le code s'arrête complètement pendant 3 secondes

Code Asynchrone (non-bloquant)

console.log("1. Début");

// Opération longue (ne bloque pas !)
setTimeout(() => {
    console.log("3. Après 3 sec");
}, 3000);

console.log("2. Fin");

// Résultat :
// 1. Début
// 2. Fin
// ... 3 secondes plus tard ...
// 3. Après 3 sec

✅ Le code continue immédiatement

Timeline SYNCHRONE :
|--- console.log("Début") ---| attend 3s |--- console.log("Fin") ---|

Timeline ASYNCHRONE :
|--- console.log("Début") ---| console.log("Fin") ---|
↓
setTimeout démarre en arrière-plan
↓
... 3 secondes ...
↓
|--- console.log("Après 3 sec") ---|

Le GROS problème du code synchrone 🚫

Imaginons qu'on charge des données depuis un serveur de manière synchrone...

Code hypothétique SYNCHRONE (n'existe pas en JS web)

console.log("1. Démarrage de l'app");

// Charger les données (BLOQUANT - 5 secondes)
const data = chargerDonneesBloquant("https://api.example.com");

console.log("2. Données:", data);
console.log("3. App prête !");

// Ce qui se passe :
// 1. "Démarrage de l'app" s'affiche
// 2. ❌ TOUT SE FIGE PENDANT 5 SECONDES
//    - Impossible de cliquer sur un bouton
//    - Impossible de scroller
//    - L'interface est MORTE
// 3. Après 5 sec, les données arrivent
// 4. Le reste du code s'exécute

❌ Conséquences catastrophiques :

C'est pourquoi JavaScript utilise l'asynchrone ! ✅

# 📞 Partie 1

Les Callbacks

Fonctions de rappel

C'est quoi un callback ? 📞

Un callback (fonction de rappel) est une fonction passée en paramètre qui sera appelée plus tard, quand l'opération asynchrone sera terminée.

Analogie : La pizzeria 🍕

Tu commandes une pizza par téléphone. Le pizzaïolo te dit : "Ça prendra 30 minutes. Donne-moi ton numéro (callback), je t'appelle quand c'est prêt".

Pendant ces 30 minutes, tu ne restes pas au téléphone à attendre (synchrone) ! Tu raccroches et tu fais autre chose. Quand la pizza est prête, le pizzaïolo t'appelle (exécute le callback).

fonction_asynchrone(paramètres, callback)
↑
Fonction à appeler quand c'est fini

setTimeout : Premier callback ⏰

setTimeout exécute une fonction après un délai. C'est l'exemple parfait de callback !

Syntaxe

setTimeout(callback, delaiEnMillisecondes);

Exemple simple

console.log("1. Début");

setTimeout(() => {
    console.log("3. Exécuté après 2 secondes");
}, 2000);

console.log("2. Fin");

// Affichage :
// 1. Début
// 2. Fin
// ... attend 2 secondes ...
// 3. Exécuté après 2 secondes

t=0ms : console.log("Début")
t=1ms : setTimeout programmé (callback enregistré)
t=2ms : console.log("Fin")
t=2000ms : Le callback s'exécute → console.log("Exécuté après 2 secondes")

Comment setTimeout fonctionne exactement ? 🔬

Décomposons étape par étape ce qui se passe avec setTimeout.

console.log("A");

setTimeout(() => {
    console.log("B");
}, 1000);

console.log("C");
  1. JavaScript lit la ligne 1
    Exécute console.log("A") → Affiche "A"
  2. JavaScript lit setTimeout
    "Ah, une fonction asynchrone !"
  3. JavaScript dit au navigateur
    "Dans 1000ms, exécute cette fonction : () => {console.log("B")}"
  4. JavaScript NE S'ARRÊTE PAS
    Il continue immédiatement à la ligne suivante
  5. JavaScript lit la ligne 5
    Exécute console.log("C") → Affiche "C"
  6. JavaScript a fini
    Il attend... il n'a plus rien à faire
  7. Après 1000ms, le navigateur dit à JavaScript
    "Hey, c'est l'heure d'exécuter ton callback !"
  8. JavaScript exécute le callback
    console.log("B") → Affiche "B"
Code JavaScript principal : Minuteur du navigateur :

console.log("A") → "A"
setTimeout(...) → Démarre minuteur 1000ms
console.log("C") → "C" Minuteur compte... 500ms
(code terminé) Minuteur compte... 1000ms
↓
callback() → "B" ← "Minuteur terminé !"

Callbacks avec des paramètres 📦

Exemple plus concret : simuler le chargement de données.

// Fonction asynchrone qui prend un callback
function chargerUtilisateur(id, callback) {
    console.log(`Chargement de l'utilisateur ${id}...`);
    
    // Simule un délai réseau de 2 secondes
    setTimeout(() => {
        const utilisateur = {
            id: id,
            nom: "Marie Dupont",
            email: "marie@example.com"
        };
        
        // Quand les données sont prêtes, on appelle le callback
        callback(utilisateur);
    }, 2000);
}

// Utilisation
console.log("Début");

chargerUtilisateur(123, (user) => {
    console.log("Utilisateur chargé:", user);
    console.log("Nom:", user.nom);
});

console.log("Fin (sans attendre)");

// Affichage :
// Début
// Chargement de l'utilisateur 123...
// Fin (sans attendre)
// ... 2 secondes plus tard ...
// Utilisateur chargé: {id: 123, nom: "Marie Dupont", ...}
// Nom: Marie Dupont

Le problème : Callback Hell 🔥

Quand on a plusieurs opérations asynchrones qui dépendent les unes des autres, les callbacks s'imbriquent et le code devient illisible !

Exemple : Charger user, puis ses posts, puis les comments

// ❌ CALLBACK HELL (Pyramide de la mort)
chargerUtilisateur(123, (utilisateur) => {
    console.log("User:", utilisateur.nom);
    
    chargerPosts(utilisateur.id, (posts) => {
        console.log("Posts:", posts.length);
        
        chargerComments(posts[0].id, (comments) => {
            console.log("Comments:", comments.length);
            
            chargerLikes(comments[0].id, (likes) => {
                console.log("Likes:", likes);
                
                // Et ça continue... 😱
                // Le code part vers la droite !
            });
        });
    });
});

// Problèmes :
// ❌ Difficile à lire (pyramide)
// ❌ Difficile à maintenir
// ❌ Gestion d'erreurs complexe
// ❌ On appelle ça "Callback Hell" ou "Pyramid of Doom"

⚠️ C'est pour résoudre ce problème que les Promises ont été créées !

# 🤝 Partie 2

Les Promises

Promesses d'avenir

C'est quoi une Promise ? 🤝

Une Promise (promesse) est un objet qui représente le résultat futur d'une opération asynchrone.

Analogie : Le ticket de commande 🎫

Tu commandes un burger au McDo. On te donne un ticket avec le numéro 42. Ce ticket est une PROMESSE que tu recevras ton burger.

Le ticket a 3 états possibles :

Promise = "Je te promets de te donner un résultat...
soit un SUCCÈS (resolve) 🎉
soit une ERREUR (reject) ❌
...mais pas tout de suite, plus tard !"

Les 3 états d'une Promise 📊

PROMISE
↓
État initial : PENDING
(en attente, en cours)
↓
Résultat ?
↙ ↘
FULFILLED REJECTED
(Résolue) ✅ (Rejetée) ❌
Succès ! Erreur !
→ then() → catch()
État Signification On peut encore changer ?
PENDING En attente, opération en cours ✅ Oui
FULFILLED Terminée avec succès ❌ Non, état final
REJECTED Terminée avec erreur ❌ Non, état final

⚠️ Important : Une fois qu'une Promise passe à FULFILLED ou REJECTED, elle ne peut PLUS changer d'état. C'est définitif !

Créer une Promise 🏗️

Syntaxe pour créer une nouvelle Promise :

const maPromise = new Promise((resolve, reject) => {
// Code asynchrone ici
// Si succès : resolve(resultat)
// Si erreur : reject(erreur)
});

Exemple simple

const promesse = new Promise((resolve, reject) => {
    // Simule une opération qui prend 2 secondes
    setTimeout(() => {
        const succes = true;
        
        if (succes) {
            resolve("Données chargées !");  // ✅ Succès
        } else {
            reject("Erreur de chargement");  // ❌ Erreur
        }
    }, 2000);
});

console.log(promesse);  // Promise {}

// Après 2 secondes :
// Promise {: "Données chargées !"}

.then() - Gérer le succès ✅

then() s'exécute quand la Promise est résolue (fulfilled).

const promesse = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("Succès !");
    }, 2000);
});

promesse.then((resultat) => {
    console.log("Résultat:", resultat);
});

// Après 2 secondes :
// Résultat: Succès !

Explication détaillée

1. new Promise() crée une promesse en état PENDING
2. setTimeout démarre (opération asynchrone)
3. .then() s'enregistre : "Appelle-moi quand c'est résolu"
4. Le code continue...
5. Après 2s, resolve("Succès !") est appelé
6. La Promise passe à FULFILLED
7. Le callback du .then() s'exécute avec "Succès !"

Exemple concret : Charger un utilisateur

function chargerUtilisateur(id) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const utilisateur = {
                id: id,
                nom: "Marie",
                email: "marie@example.com"
            };
            resolve(utilisateur);
        }, 2000);
    });
}

chargerUtilisateur(123).then((user) => {
    console.log("User chargé:", user.nom);
});

// Après 2s : User chargé: Marie

.catch() - Gérer les erreurs ❌

catch() s'exécute quand la Promise est rejetée (rejected).

const promesse = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject("Erreur serveur !");  // ❌ Rejette la promesse
    }, 2000);
});

promesse
    .then((resultat) => {
        console.log("Succès:", resultat);
    })
    .catch((erreur) => {
        console.log("Erreur:", erreur);
    });

// Après 2 secondes :
// Erreur: Erreur serveur !

Exemple avec gestion d'erreur

function chargerUtilisateur(id) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (id <= 0) {
                reject("ID invalide");  // ❌ Erreur
                return;
            }
            
            const utilisateur = {
                id: id,
                nom: "Marie"
            };
            resolve(utilisateur);  // ✅ Succès
        }, 1000);
    });
}

// Cas de succès
chargerUtilisateur(123)
    .then(user => console.log("User:", user.nom))
    .catch(err => console.log("Erreur:", err));
// User: Marie

// Cas d'erreur
chargerUtilisateur(-5)
    .then(user => console.log("User:", user.nom))
    .catch(err => console.log("Erreur:", err));
// Erreur: ID invalide

Chaînage de Promises ⛓️

On peut chaîner plusieurs .then() pour des opérations successives. Beaucoup plus lisible que les callbacks !

❌ Avec Callbacks (Hell)

chargerUser(123, user => {
    chargerPosts(user.id, posts => {
        chargerComments(posts[0].id, 
            comments => {
                console.log(comments);
            });
    });
});

✅ Avec Promises (Propre)

chargerUser(123)
    .then(user => chargerPosts(user.id))
    .then(posts => chargerComments(posts[0].id))
    .then(comments => console.log(comments))
    .catch(err => console.log(err));

Comment ça marche ?

chargerUser(123)
↓ retourne une Promise
.then(user => chargerPosts(user.id))
↓ chargerPosts retourne une Promise
.then(posts => chargerComments(posts[0].id))
↓ chargerComments retourne une Promise
.then(comments => console.log(comments))
↓ si ERREUR à n'importe quelle étape
.catch(err => console.log(err))

✅ Chaque .then() peut retourner une nouvelle Promise, permettant de chaîner les opérations de manière lisible et linéaire !

.finally() - Toujours exécuté 🏁

finally() s'exécute dans tous les cas, que la Promise soit résolue ou rejetée.

chargerUtilisateur(123)
    .then(user => {
        console.log("Succès:", user);
    })
    .catch(err => {
        console.log("Erreur:", err);
    })
    .finally(() => {
        console.log("Opération terminée (succès ou erreur)");
    });

// Si succès :
// Succès: {id: 123, nom: "Marie"}
// Opération terminée (succès ou erreur)

// Si erreur :
// Erreur: Utilisateur introuvable
// Opération terminée (succès ou erreur)

Cas d'usage courant : Cacher un loader

// Afficher un indicateur de chargement
afficherLoader();

chargerDonnees()
    .then(data => afficherDonnees(data))
    .catch(err => afficherErreur(err))
    .finally(() => {
        cacherLoader();  // Toujours cacher le loader
    });

Utilité : Parfait pour du code de nettoyage qui doit s'exécuter peu importe le résultat (fermer connexion, cacher loader, etc.)

# ✨ Partie 3

Async / Await

La syntaxe moderne et élégante

C'est quoi async/await ? ✨

async/await est une syntaxe moderne qui rend le code asynchrone aussi lisible que du code synchrone.

Analogie : Lire un livre vs regarder un film 📖🎬

Promises avec .then() : C'est comme lire un livre où il faut tourner les pages dans le bon ordre, mais les chapitres ne se suivent pas naturellement.

Async/await : C'est comme regarder un film où tout se déroule de manière fluide et séquentielle. Tu suis l'histoire ligne par ligne, naturellement !

Avec .then() (ancien)

chargerUser(123)
    .then(user => {
        return chargerPosts(user.id);
    })
    .then(posts => {
        console.log(posts);
    })
    .catch(err => {
        console.log(err);
    });

Avec async/await (moderne)

try {
    const user = await chargerUser(123);
    const posts = await chargerPosts(user.id);
    console.log(posts);
} catch (err) {
    console.log(err);
}

✅ C'est la MÊME chose, juste écrit différemment ! Async/await est du sucre syntaxique par-dessus les Promises.

Le mot-clé async 🔑

async devant une fonction signifie : "Cette fonction retourne TOUJOURS une Promise".

Fonction normale

function saluer() {
    return "Bonjour";
}

const resultat = saluer();
console.log(resultat);  // "Bonjour" (string)

Fonction async

async function saluer() {
    return "Bonjour";
}

const resultat = saluer();
console.log(resultat);  // Promise {: "Bonjour"}

// Pour obtenir la valeur
saluer().then(msg => console.log(msg));  // "Bonjour"
function normale() → retourne la valeur directement
async function() → retourne TOUJOURS une Promise
(même si tu return une valeur simple)

Équivalence

// Ces deux fonctions sont équivalentes !

async function obtenir() {
    return 42;
}

function obtenir() {
    return Promise.resolve(42);
}

// Les deux retournent : Promise {: 42}

Le mot-clé await ⏸️

await = "Attend que cette Promise se résolve, puis continue".

⚠️ RÈGLE ABSOLUE : On ne peut utiliser await QUE dans une fonction async !

// ❌ ERREUR : await sans async
function maFonction() {
    const result = await promesse();  // ❌ Erreur de syntaxe !
}

// ✅ CORRECT : await dans une fonction async
async function maFonction() {
    const result = await promesse();  // ✅ OK
}

Exemple concret

function attendreDeuxSecondes() {
    return new Promise(resolve => {
        setTimeout(() => resolve("Terminé !"), 2000);
    });
}

async function tester() {
    console.log("Début");
    
    const resultat = await attendreDeuxSecondes();
    // ⏸️ Le code S'ARRÊTE ICI et attend 2 secondes
    
    console.log(resultat);
    console.log("Fin");
}

tester();

// Affichage :
// Début
// ... attend 2 secondes ...
// Terminé !
// Fin

Comment await fonctionne exactement ? 🔬

Décomposons ligne par ligne ce qui se passe avec await.

async function chargerDonnees() {
    console.log("1. Début");
    
    const user = await chargerUtilisateur(123);
    
    console.log("2. User:", user.nom);
    console.log("3. Fin");
}
  1. Ligne 1 : Fonction appelée
    chargerDonnees() commence à s'exécuter
  2. Ligne 2 : console.log
    Affiche "1. Début" immédiatement
  3. Ligne 4 : await rencontré
    chargerUtilisateur(123) est appelé → retourne une Promise PENDING
  4. Le mot-clé await dit : "PAUSE !"
    La fonction chargerDonnees() est MISE EN PAUSE
    MAIS le reste du programme continue normalement !
  5. Attente de la Promise
    La fonction attend que la Promise se résolve
  6. Promise résolue
    Quand la Promise se résout, la fonction REPREND
    await extrait la VALEUR de la Promise
  7. Ligne 6 : Continuation
    user contient maintenant la valeur
    Le code continue normalement

await "déballé" la Promise et te donne directement la valeur, comme si c'était du code synchrone !

Gestion des erreurs avec try/catch ❌

Avec async/await, on utilise try/catch pour gérer les erreurs (comme en Java, C#, etc.).

Sans gestion d'erreur (❌ DANGEREUX)

async function charger() {
    const user = await chargerUtilisateur(123);
    // Si chargerUtilisateur échoue → ERREUR NON GÉRÉE !
    console.log(user);
}

Avec try/catch (✅ SÉCURISÉ)

async function charger() {
    try {
        const user = await chargerUtilisateur(123);
        console.log("Succès:", user);
    } catch (erreur) {
        console.log("Erreur:", erreur);
    }
}

// Si succès → "Succès: {id: 123, nom: "Marie"}"
// Si erreur → "Erreur: Utilisateur introuvable"

Avec finally

async function charger() {
    try {
        afficherLoader();
        const user = await chargerUtilisateur(123);
        afficherUser(user);
    } catch (erreur) {
        afficherErreur(erreur);
    } finally {
        cacherLoader();  // Toujours exécuté
    }
}

Plusieurs await successifs 📝

On peut utiliser plusieurs await dans la même fonction. Chaque await ATTEND que la Promise précédente se résolve.

Exécution séquentielle

async function chargerTout() {
    console.log("Début");
    
    const user = await chargerUtilisateur(123);
    console.log("User chargé:", user.nom);
    
    const posts = await chargerPosts(user.id);
    console.log("Posts chargés:", posts.length);
    
    const comments = await chargerComments(posts[0].id);
    console.log("Comments chargés:", comments.length);
    
    console.log("Tout est chargé !");
}

// Affichage (étape par étape) :
// Début
// ... attend chargerUtilisateur ...
// User chargé: Marie
// ... attend chargerPosts ...
// Posts chargés: 5
// ... attend chargerComments ...
// Comments chargés: 12
// Tout est chargé !

0s : Début
0-2s : Chargement user...
2s : User chargé
2-3s : Chargement posts...
3s : Posts chargés
3-4s : Chargement comments...
4s : Comments chargés

Await en parallèle avec Promise.all ⚡

Si les opérations sont indépendantes, on peut les lancer en parallèle avec Promise.all() !

❌ Séquentiel (lent)

async function charger() {
    const user = await chargerUser();
    const posts = await chargerPosts();
    const comments = await chargerComments();
    
    // Total : 6 secondes
    // (2s + 2s + 2s)
}

✅ Parallèle (rapide)

async function charger() {
    const resultats = await Promise.all([
        chargerUser(),
        chargerPosts(),
        chargerComments()
    ]);
    
    // Total : 2 secondes
    // (les 3 en même temps !)
}

Avec destructuration

async function charger() {
    const [user, posts, comments] = await Promise.all([
        chargerUser(),
        chargerPosts(),
        chargerComments()
    ]);
    
    console.log(user, posts, comments);
}

// Toutes les requêtes se font EN MÊME TEMPS !

✅ Gain de temps énorme quand les opérations sont indépendantes !

# 🌐 Partie 4

Fetch API

Faire des requêtes HTTP

C'est quoi Fetch API ? 🌐

Fetch est une fonction JavaScript pour faire des requêtes HTTP (appeler des APIs, charger des données...).

Analogie : Commander sur Internet 📦

Fetch, c'est comme commander un produit sur Amazon :

Syntaxe de base

fetch(url)
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log(error));

fetch() retourne une Promise, donc on peut utiliser .then() ou async/await !

Premier exemple avec Fetch 🚀

API publique : JSONPlaceholder

// Charger une liste d'utilisateurs
fetch("https://jsonplaceholder.typicode.com/users")
    .then(response => {
        console.log("Réponse reçue:", response);
        return response.json();  // Convertit en JSON
    })
    .then(users => {
        console.log("Utilisateurs:", users);
        console.log("Premier user:", users[0].name);
    })
    .catch(error => {
        console.log("Erreur:", error);
    });

// Affichage :
// Réponse reçue: Response {status: 200, ok: true, ...}
// Utilisateurs: [{id: 1, name: "Leanne Graham", ...}, ...]
// Premier user: Leanne Graham

Avec async/await (plus lisible)

async function chargerUtilisateurs() {
    try {
        const response = await fetch("https://jsonplaceholder.typicode.com/users");
        const users = await response.json();
        
        console.log("Utilisateurs:", users);
        console.log("Premier:", users[0].name);
    } catch (error) {
        console.log("Erreur:", error);
    }
}

chargerUtilisateurs();

L'objet Response 📦

Fetch retourne un objet Response qui contient des informations sur la réponse HTTP.

const response = await fetch("https://api.example.com/data");

console.log(response);
Response {
status: 200, // Code HTTP (200 = OK)
ok: true, // true si status 200-299
statusText: "OK", // Message du statut
headers: Headers {...}, // En-têtes HTTP
url: "https://...", // URL appelée
body: ReadableStream, // Corps de la réponse
...
}

Propriétés importantes

Propriété Description Exemple
status Code HTTP 200, 404, 500...
ok Succès ? (200-299) true / false
json() Convertit body en JSON await response.json()
text() Convertit body en texte await response.text()

Vérifier le statut de la réponse ✅

⚠️ Important : Fetch ne rejette PAS la Promise pour les erreurs HTTP (404, 500...). Il faut vérifier manuellement !

❌ Sans vérification

const response = await fetch(url);
const data = await response.json();

// Si erreur 404 → essaie quand même
// de parser le JSON → ERREUR !

✅ Avec vérification

const response = await fetch(url);

if (!response.ok) {
    throw new Error(`Erreur ${response.status}`);
}

const data = await response.json();

Fonction helper complète

async function fetchJSON(url) {
    try {
        const response = await fetch(url);
        
        // Vérifier le statut
        if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }
        
        // Convertir en JSON
        const data = await response.json();
        return data;
        
    } catch (error) {
        console.error("Erreur Fetch:", error.message);
        throw error;  // Repropager l'erreur
    }
}

// Utilisation
const users = await fetchJSON("https://api.example.com/users");

Fetch POST - Envoyer des données 📤

Par défaut, fetch fait un GET. Pour envoyer des données (POST, PUT...), on passe un objet de configuration.

POST : Créer une ressource

async function creerUtilisateur(user) {
    const response = await fetch("https://api.example.com/users", {
        method: "POST",                    // Méthode HTTP
        headers: {
            "Content-Type": "application/json"  // Type de contenu
        },
        body: JSON.stringify(user)         // Données (en JSON)
    });
    
    if (!response.ok) {
        throw new Error(`Erreur ${response.status}`);
    }
    
    const data = await response.json();
    return data;
}

// Utilisation
const nouveauUser = {
    nom: "Marie",
    email: "marie@example.com"
};

const resultat = await creerUtilisateur(nouveauUser);
console.log("Créé:", resultat);

PUT : Modifier une ressource

async function modifierUtilisateur(id, user) {
    const response = await fetch(`https://api.example.com/users/${id}`, {
        method: "PUT",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify(user)
    });
    
    return await response.json();
}

Fetch DELETE - Supprimer une ressource 🗑️

async function supprimerUtilisateur(id) {
    const response = await fetch(`https://api.example.com/users/${id}`, {
        method: "DELETE"
    });
    
    if (!response.ok) {
        throw new Error(`Erreur ${response.status}`);
    }
    
    // Certaines APIs retournent du contenu, d'autres non
    if (response.status === 204) {
        return null;  // Pas de contenu
    }
    
    return await response.json();
}

// Utilisation
await supprimerUtilisateur(123);
console.log("Utilisateur supprimé");

Résumé des méthodes HTTP

Méthode Action Exemple
GET Récupérer des données Lister les users
POST Créer une ressource Créer un user
PUT Modifier une ressource (complète) Modifier un user
PATCH Modifier partiellement Changer juste l'email
DELETE Supprimer une ressource Supprimer un user
# 💡 Partie 5

Exemples Pratiques Complets

Tout mettre en pratique

Exemple 1 : Liste d'utilisateurs 👥

HTML

<button id="charger-btn">Charger les utilisateurs</button>
<div id="loader" style="display: none;">Chargement...</div>
<ul id="liste-users"></ul>

JavaScript

const bouton = document.querySelector("#charger-btn");
const loader = document.querySelector("#loader");
const liste = document.querySelector("#liste-users");

async function chargerUtilisateurs() {
    try {
        // Afficher le loader
        loader.style.display = "block";
        bouton.disabled = true;
        
        // Requête
        const response = await fetch("https://jsonplaceholder.typicode.com/users");
        
        if (!response.ok) {
            throw new Error(`Erreur HTTP ${response.status}`);
        }
        
        const users = await response.json();
        
        // Afficher les utilisateurs
        liste.innerHTML = "";
        users.forEach(user => {
            const li = document.createElement("li");
            li.textContent = `${user.name} - ${user.email}`;
            liste.appendChild(li);
        });
        
    } catch (error) {
        alert("Erreur: " + error.message);
    } finally {
        // Cacher le loader (toujours exécuté)
        loader.style.display = "none";
        bouton.disabled = false;
    }
}

bouton.addEventListener("click", chargerUtilisateurs);

Exemple 2 : Formulaire POST 📝

HTML

<form id="user-form">
    <input type="text" id="nom" placeholder="Nom" required>
    <input type="email" id="email" placeholder="Email" required>
    <button type="submit">Créer</button>
</form>
<div id="message"></div>

JavaScript

const form = document.querySelector("#user-form");
const messageDiv = document.querySelector("#message");

async function creerUtilisateur(event) {
    event.preventDefault();
    
    // Récupérer les données du formulaire
    const nom = document.querySelector("#nom").value;
    const email = document.querySelector("#email").value;
    
    const userData = {
        name: nom,
        email: email
    };
    
    try {
        messageDiv.textContent = "Création en cours...";
        
        const response = await fetch("https://jsonplaceholder.typicode.com/users", {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(userData)
        });
        
        if (!response.ok) {
            throw new Error("Erreur lors de la création");
        }
        
        const newUser = await response.json();
        
        messageDiv.textContent = `✅ Utilisateur créé : ${newUser.name}`;
        messageDiv.style.color = "green";
        
        // Réinitialiser le formulaire
        form.reset();
        
    } catch (error) {
        messageDiv.textContent = `❌ Erreur : ${error.message}`;
        messageDiv.style.color = "red";
    }
}

form.addEventListener("submit", creerUtilisateur);

Exemple 3 : Recherche avec debounce ⏱️

Recherche qui attend que l'utilisateur ait fini de taper avant de lancer la requête.

HTML

<input type="text" id="recherche" placeholder="Rechercher un user...">
<ul id="resultats"></ul>

JavaScript

const input = document.querySelector("#recherche");
const resultats = document.querySelector("#resultats");
let timeoutId;

async function rechercher(terme) {
    if (terme.length < 2) {
        resultats.innerHTML = "";
        return;
    }
    
    try {
        const response = await fetch("https://jsonplaceholder.typicode.com/users");
        const users = await response.json();
        
        // Filtrer les résultats
        const filtres = users.filter(user => 
            user.name.toLowerCase().includes(terme.toLowerCase())
        );
        
        // Afficher
        resultats.innerHTML = "";
        if (filtres.length === 0) {
            resultats.innerHTML = "
  • Aucun résultat
  • "; } else { filtres.forEach(user => { const li = document.createElement("li"); li.textContent = user.name; resultats.appendChild(li); }); } } catch (error) { resultats.innerHTML = `
  • Erreur: ${error.message}
  • `; } } input.addEventListener("input", (event) => { // Annuler le timeout précédent clearTimeout(timeoutId); // Lancer un nouveau timeout (300ms) timeoutId = setTimeout(() => { rechercher(event.target.value); }, 300); });
    # 🎓 Récapitulatif

    Ce qu'on a appris

    Résumé complet 📚

    Concept Syntaxe Usage
    Callback setTimeout(callback, 1000) Fonction appelée plus tard
    Promise new Promise((resolve, reject) => ...) Résultat futur d'une opération
    .then() promise.then(data => ...) Gérer le succès
    .catch() promise.catch(err => ...) Gérer l'erreur
    .finally() promise.finally(() => ...) Toujours exécuté
    async async function() {...} Fonction qui retourne une Promise
    await const data = await promise Attendre une Promise
    fetch fetch(url) Requête HTTP
    Promise.all await Promise.all([p1, p2]) Attendre plusieurs Promises

    Bonnes pratiques 💡

    1. Préfère async/await à .then()
      Plus lisible et plus facile à déboguer
    2. TOUJOURS gérer les erreurs
      Utilise try/catch avec async/await
    3. Vérifie response.ok avec fetch
      Les erreurs HTTP ne rejettent pas automatiquement
    4. Utilise Promise.all pour le parallèle
      Quand les opérations sont indépendantes
    5. Pense aux loading indicators
      Affiche un loader pendant les opérations asynchrones
    6. Nettoie avec finally
      Pour cacher les loaders, fermer connexions, etc.

    L'asynchrone est partout en JavaScript moderne ! APIs, bases de données, fichiers... Maîtriser ces concepts est essentiel.

    Comparaison finale 🆚

    Le MÊME code écrit de 3 façons différentes :

    1. Callbacks (ancien, compliqué)

    chargerUser(123, (user, err) => {
        if (err) {
            console.log(err);
            return;
        }
        chargerPosts(user.id, (posts, err) => {
            if (err) {
                console.log(err);
                return;
            }
            console.log(posts);
        });
    });

    2. Promises avec .then()

    chargerUser(123)
        .then(user => chargerPosts(user.id))
        .then(posts => console.log(posts))
        .catch(err => console.log(err));

    3. Async/Await (moderne, recommandé)

    async function afficherPosts() {
        try {
            const user = await chargerUser(123);
            const posts = await chargerPosts(user.id);
            console.log(posts);
        } catch (err) {
            console.log(err);
        }
    }
    
    afficherPosts();

    ✅ Utilisez async/await ! C'est la syntaxe moderne, lisible et recommandée.

    🎓 Fin du cours

    JavaScript Asynchrone

    Vous maîtrisez maintenant :

    ⏱️ Le concept d'asynchrone

    📞 Les callbacks

    🤝 Les Promises (then, catch, finally)

    ✨ Async/Await (syntaxe moderne)

    🌐 Fetch API (requêtes HTTP)

    ❌ La gestion des erreurs

    Pratiquez avec des APIs réelles ! 💪

    Formation DWWM - 2026