Objectifs de cette leçon
- Créer une Promise
- Utiliser then/catch/finally
- Comprendre l'ordre d'exécution asynchrone
Promesses en JavaScript 🤞
Les promesses gerent les operations asynchrones : appels reseau, lecture de fichiers, delais... Elles representent une valeur qui sera disponible maintenant, plus tard, ou jamais.
1. Pourquoi les promesses ? 🤔
// ❌ Callback hell (cauchemar) fetchUser(id, (user) => { getOrders(user.id, (orders) => { getOrderDetails(orders[0].id, (details) => { console.log(details); // Imbrication infinie... }); }); }); // ✅ Avec Promesses fetchUser(id) .then(user => getOrders(user.id)) .then(orders => getOrderDetails(orders[0].id)) .then(details => console.log(details)) .catch(error => console.error(error));
2. Creer une promesse 🏗️
const maPromesse = new Promise((resolve, reject) => { // Code asynchrone ici const succes = true; if (succes) { resolve("Operation reussie !"); // Promesse tenue } else { reject(new Error("Echec !")); // Promesse rompue } }); // Utiliser la promesse maPromesse .then(resultat => { console.log(resultat); // "Operation reussie !" }) .catch(erreur => { console.error(erreur.message); // "Echec !" });
Trois etats d'une promesse
| Etat | Description | Resultat |
|---|---|---|
| Pending (en attente) | L'operation n'est pas finie | Aucun |
| Fulfilled (tenue) | L'operation a reussi | resolve(valeur) |
| Rejected (rompue) | L'operation a echoue | reject(erreur) |
3. then, catch, finally 🔄
function fetchUser(id) { return new Promise((resolve, reject) => { setTimeout(() => { if (id > 0) { resolve({ id, nom: "Alice", email: "alice@email.com" }); } else { reject(new Error("ID invalide")); } }, 1000); }); } fetchUser(1) .then(user => { console.log("Utilisateur :", user.nom); return user.email; // La valeur retournee devient la valeur du then suivant }) .then(email => { console.log("Email :", email); }) .catch(erreur => { console.error("Erreur :", erreur.message); }) .finally(() => { console.log("Operation terminee (succes ou echec)"); });
💡
finallys'execute toujours, que la promesse soit tenue ou rompue. Utile pour le nettoyage.
4. Promesses imbriquees et chaining 📦
function fetchUser(id) { return new Promise(resolve => { setTimeout(() => resolve({ id, nom: "Alice" }), 1000); }); } function fetchPosts(userId) { return new Promise(resolve => { setTimeout(() => resolve([ { id: 1, titre: "Post 1" }, { id: 2, titre: "Post 2" } ]), 1000); }); } // Chaining fetchUser(1) .then(user => { console.log("User :", user.nom); return fetchPosts(user.id); // Retourne une nouvelle promesse }) .then(posts => { console.log("Posts :", posts.length); }) .catch(err => { console.error("Erreur :", err); });
5. Promise.all — executer en parallele ⚡
const promesse1 = fetch("https://api.example.com/users").then(r => r.json()); const promesse2 = fetch("https://api.example.com/posts").then(r => r.json()); const promesse3 = fetch("https://api.example.com/comments").then(r => r.json()); // Tout execute en parallele, on attend les 3 Promise.all([promesse1, promesse2, promesse3]) .then(([users, posts, comments]) => { console.log("Users :", users.length); console.log("Posts :", posts.length); console.log("Comments :", comments.length); }) .catch(erreur => { // Si UNE SEULE promesse echoue, tout echoue console.error("Une erreur :", erreur); });
⚠️
Promise.allechoue completement si une seule promesse echoue. UtilisePromise.allSettledpour ignorer les echecs.
6. Promise.allSettled — sans echec 🛡️
const promesses = [ Promise.resolve("Succes 1"), Promise.reject(new Error("Echec")), Promise.resolve("Succes 2") ]; Promise.allSettled(promesses) .then(resultats => { resultats.forEach(r => { if (r.status === "fulfilled") { console.log("Succes :", r.value); } else { console.log("Echec :", r.reason.message); } }); }); // Affiche : // Succes : Succes 1 // Echec : Echec // Succes : Succes 2
7. Promise.race — le premier arrive gagne 🏁
function timeout(ms) { return new Promise((_, reject) => { setTimeout(() => reject(new Error("Timeout !")), ms); }); } const fetchAvecTimeout = Promise.race([ fetch("https://api.example.com/data"), timeout(5000) // Timeout apres 5 secondes ]); fetchAvecTimeout .then(reponse => console.log("Donnees recues")) .catch(erreur => console.error(erreur.message)); // "Timeout !" si > 5s
8. Promise.any — le premier succes 🏆
const promesses = [ fetch("https://api1.example.com/data"), fetch("https://api2.example.com/data"), fetch("https://api3.example.com/data") ]; // Le premier succes est utilise Promise.any(promesses) .then(reponse => { console.log("Premiere reponse recue :", reponse); }) .catch(AggregateError => { // Toutes les promesses ont echoue console.error("Toutes les sources ont echoue"); });
9. La microtask queue et l'ordre d'execution ⏱️
console.log("1. Debut"); setTimeout(() => { console.log("2. setTimeout (macrotache)"); }, 0); Promise.resolve().then(() => { console.log("3. Promise.then (microtache)"); }); console.log("4. Fin"); // Resultat : // 1. Debut // 4. Fin // 3. Promise.then (microtache) // 2. setTimeout (macrotache)
💡 Ordre de priorite :
- Code synchrone (s'execute immediatement)
- Microtaches (Promises —
then,catch,finally)- Macrotaches (
setTimeout,setInterval, I/O)
setTimeout(() => console.log("1"), 0); Promise.resolve().then(() => console.log("2")); Promise.resolve().then(() => console.log("3")); setTimeout(() => console.log("4"), 0); // Resultat : 2, 3, 1, 4 // Les microtaches (2, 3) passent AVANT les macrotaches (1, 4)
10. Exemple concret : fetch API 🌐
// GET simple fetch("https://jsonplaceholder.typicode.com/users/1") .then(reponse => { if (!reponse.ok) { throw new Error(`Erreur HTTP : ${reponse.status}`); } return reponse.json(); }) .then(donnees => { console.log("Utilisateur :", donnees.name); }) .catch(erreur => { console.error("Erreur :", erreur.message); }); // POST avec donnees fetch("https://jsonplaceholder.typicode.com/posts", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ titre: "Nouveau post", corps: "Contenu du post", userId: 1 }) }) .then(r => r.json()) .then(donnees => console.log("Cree :", donnees));
11. Exercices pour toi 🎯
Exercice 1 : Delai avec promesse
Cree une function delai(ms) qui retourne une promesse qui se resout apres ms millisecondes.
Exercice 2 : Retry
Cree une function fetchAvecRetry(url, tentatives) qui reessaie l'appel en cas d'echec.
Exercice 3 : Serie de promesses Execute 3 fetch en serie (le 2em depend du 1er) avec gestion d'erreur globale.
⚡ Simulateur — Promesses
Étape 1/6new Promise() crée une promesse. La fonction exécuteur reçoit resolve et reject. La promesse est en état "pending" (en attente).