// js · Web Platform Advent #2
Les promesses JavaScript : guide pratique
Comprendre les promesses JavaScript — leur création, then/catch/finally, le chaînage et la combinaison avec Promise.all, race, any et allSettled — avec des exemples exécutables et les pièges courants.
Une promesse est un objet qui représente une valeur pas encore disponible. C'est le socle du JavaScript asynchrone : fetch(), les minuteurs, les lectures de fichiers en Node et la plupart des API modernes renvoient des promesses. Une promesse est toujours dans l'un de trois états — en attente (pending), tenue (fulfilled) ou rompue (rejected) — et une fois réglée, elle ne change plus jamais.
Créer une promesse
La plupart du temps, vous consommez des promesses qu'une API vous fournit. Mais on en crée une soi-même avec le constructeur Promise, qui reçoit une fonction exécutrice avec resolve et reject :
const wait = (ms) => new Promise((resolve) => {
setTimeout(resolve, ms);
});
const fetchUser = (id) => new Promise((resolve, reject) => {
if (!id) reject(new Error('id requis'));
else resolve({ id, name: 'Ada' });
}); Appeler resolve(valeur) tient la promesse avec cette valeur ; appeler reject(erreur) la rompt. Toute exception levée de façon synchrone dans l'exécutrice rompt aussi la promesse.
then, catch et finally
On lit le résultat d'une promesse avec .then() pour le succès, .catch() pour l'échec, et .finally() pour un nettoyage qui s'exécute dans les deux cas :
fetchUser(42)
.then((user) => console.log('Reçu', user.name))
.catch((err) => console.error('Échec :', err.message))
.finally(() => console.log('Terminé')); .then() peut prendre deux arguments — onFulfilled et onRejected — mais un .catch() séparé en fin de chaîne est plus clair et attrape aussi les erreurs levées dans les .then() précédents.
Le chaînage : le vrai super-pouvoir
Chaque .then() renvoie une nouvelle promesse, d'où le chaînage. Ce que vous renvoyez d'un gestionnaire devient l'entrée du suivant. Surtout, si vous renvoyez une promesse, la chaîne attend qu'elle soit réglée avant de continuer :
fetch('/api/user')
.then((res) => res.json()) // renvoie une promesse → la chaîne attend
.then((user) => fetch('/api/posts?user=' + user.id))
.then((res) => res.json())
.then((posts) => console.log(posts.length, 'articles'))
.catch((err) => console.error(err)); Un seul .catch() à la fin gère un rejet de n'importe quelle étape au-dessus, ce qui explique pourquoi le chaînage l'emporte sur l'imbrication des callbacks.
Exécuter des promesses ensemble
Quand les tâches ne dépendent pas les unes des autres, lancez-les en parallèle et combinez les résultats. Quatre méthodes statiques couvrent les cas courants :
Promise.all([...])— attend que toutes soient tenues ; rompt dès qu'une est rompue. Renvoie un tableau de résultats dans l'ordre.Promise.allSettled([...])— attend que toutes se terminent et ne rompt jamais ; renvoie un tableau d'objets{ status, value }ou{ status, reason }.Promise.race([...])— se règle avec la première promesse réglée, qu'elle soit tenue ou rompue.Promise.any([...])— se règle avec la première promesse tenue ; ne rompt que si elles sont toutes rompues.
// Récupérer trois ressources d'un coup, échouer si l'une échoue
const [user, posts, prefs] = await Promise.all([
fetch('/api/user').then((r) => r.json()),
fetch('/api/posts').then((r) => r.json()),
fetch('/api/prefs').then((r) => r.json()),
]);
// Pareil, mais en tolérant les échecs individuels
const results = await Promise.allSettled([taskA(), taskB(), taskC()]);
results.forEach((r) => {
if (r.status === 'fulfilled') console.log('ok', r.value);
else console.warn('échec', r.reason);
}); Pièges courants
- Oublier le return. Dans un
.then(), si vous appelez une promesse sans lareturn, la chaîne ne l'attend pas — vous perdez l'ordre et la gestion d'erreur. - Rejets non gérés. Une promesse sans
.catch()(ou sanstry/catchautour deawait) produit ununhandledrejection. Gérez toujours les erreurs en fin de chaîne. - Mélanger callbacks et promesses. N'appelez pas
resolvedeux fois, niresolveetrejectensemble — seul le premier appel compte ; le reste est ignoré en silence. - L'exécutrice s'exécute aussitôt. La fonction passée à
new Promise()s'exécute de façon synchrone, immédiatement — seuls les callbacks.then()sont différés.
Aide-mémoire
| Objectif | Méthode |
|---|---|
| Gérer le succès | .then(onFulfilled) |
| Gérer l'échec | .catch(onRejected) |
| Nettoyer dans tous les cas | .finally(fn) |
| Toutes doivent réussir | Promise.all |
| Récupérer chaque issue | Promise.allSettled |
| La première réglée | Promise.race |
| La première réussie | Promise.any |
Les promesses sont la tuyauterie sous async/await, qui n'est qu'une syntaxe plus agréable au-dessus des mêmes objets. Une fois le chaînage et les quatre combinateurs devenus naturels, le JavaScript asynchrone cesse d'intimider.