À propos de ce cours
Chapitre 18 — La programmation asynchrone · Leçon 5 : async et await
• déclarer une fonction
async et savoir ce qu'elle renvoie ;• attendre une promesse avec
await; • gérer les erreurs avec
try / catch / finally; • choisir entre exécution séquentielle et parallèle, et éviter les pièges courants.
1. Une syntaxe plus simple pour les promesses
async et await ne remplacent pas les promesses : c'est une autre façon d'écrire du code qui les utilise,
qui ressemble à du code synchrone.
- Une fonction déclarée
asyncrenvoie toujours une promesse. - À l'intérieur,
await promessesuspend la fonction (pas le programme !) jusqu'à ce que la promesse soit réglée, puis donne sa valeur.
async function direBonjour() {
return "Bonjour"; // la valeur est automatiquement enveloppée dans une promesse
}
const resultat = direBonjour();
console.log(resultat instanceof Promise); // true
resultat.then((texte) => console.log(texte));
function attendre(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function compteARebours() {
for (let i = 3; i >= 1; i--) {
console.log(i);
await attendre(1000); // pause de la FONCTION, pas du programme
}
console.log("Partez !");
}
compteARebours();
console.log("Le programme continue pendant le compte à rebours");
Résultat dans la console
true 3 Le programme continue pendant le compte à rebours Bonjour 2 1 Partez !
« Bonjour » s'affiche après la ligne « Le programme continue… » : .then est une microtâche (leçon 2).
Pendant chaque await, la fonction est en pause, mais la boucle d'événements continue de tourner.
2. Le scénario complet, lu de haut en bas
Le même enchaînement qu'aux leçons 3 et 4, avec try / catch pour les erreurs :
function chargerUtilisateur(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id <= 0) reject(new Error("Identifiant invalide"));
else resolve({ id, nom: "Amina" });
}, 300);
});
}
function chargerCommandes(utilisateur) {
return new Promise((resolve) =>
setTimeout(() => resolve([{ ref: "C-101" }, { ref: "C-102" }]), 300));
}
function chargerDetails(commande) {
return new Promise((resolve) =>
setTimeout(() => resolve({ ref: commande.ref, articles: [12.5, 7, 30] }), 300));
}
function calculerTotal(details) {
return new Promise((resolve) =>
setTimeout(() => resolve(details.articles.reduce((s, p) => s + p, 0)), 300));
}
// Le même enchaînement qu'aux leçons 3 et 4, lu comme du code synchrone
async function afficherTotal(id) {
try {
const utilisateur = await chargerUtilisateur(id);
const commandes = await chargerCommandes(utilisateur);
const details = await chargerDetails(commandes[0]);
const total = await calculerTotal(details);
console.log(`${utilisateur.nom} — ${details.ref} : ${total} DT`);
} catch (err) {
console.log("Erreur :", err.message);
} finally {
console.log(`Fin du traitement pour l'id ${id}`);
}
}
async function main() {
await afficherTotal(1);
await afficherTotal(-1);
}
main();
Résultat dans la console
Amina — C-101 : 49.5 DT Fin du traitement pour l'id 1 Erreur : Identifiant invalide Fin du traitement pour l'id -1
| Promesses | async / await |
|---|---|
p.then(v => …) | const v = await p; |
.catch(e => …) | try { … } catch (e) { … } |
.finally(() => …) | finally { … } |
return Promise.resolve(v) | return v; dans une fonction async |
return Promise.reject(e) | throw e; dans une fonction async |
3. Séquentiel ou parallèle ?
await attend. Si l'on écrit trois await à la suite pour des opérations indépendantes, on perd du temps. On lance alors tout, puis on attend l'ensemble avec Promise.all.
function charger(nom, ms) {
return new Promise((resolve) => setTimeout(() => resolve(nom), ms));
}
const secondes = (debut) => `${Math.round((Date.now() - debut) / 100) / 10} s`;
async function enSequence() {
const debut = Date.now();
const meteo = await charger("météo", 1000);
const actus = await charger("actualités", 800);
const agenda = await charger("agenda", 1200);
console.log("Séquence :", [meteo, actus, agenda], secondes(debut));
}
async function enParallele() {
const debut = Date.now();
const [meteo, actus, agenda] = await Promise.all([
charger("météo", 1000),
charger("actualités", 800),
charger("agenda", 1200),
]);
console.log("Parallèle :", [meteo, actus, agenda], secondes(debut));
}
async function main() {
await enSequence();
await enParallele();
}
main();
Résultat dans la console
Séquence : [ 'météo', 'actualités', 'agenda' ] 3 s Parallèle : [ 'météo', 'actualités', 'agenda' ] 1.2 s

Figure 5 — Opérations indépendantes : Promise.all divise ici le temps par plus de deux.
Règle simple : si l'étape B a besoin du résultat de l'étape A →
await l'un après l'autre.
Si les étapes sont indépendantes → await Promise.all([...]). 4. Pièges fréquents
4.1 await dans forEach
forEach n'attend pas les fonctions async qu'on lui donne : la boucle se termine aussitôt.
function attendre(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
const fichiers = ["a.txt", "b.txt", "c.txt"];
async function avecForEach() {
fichiers.forEach(async (f) => {
await attendre(100);
console.log("forEach a traité", f);
});
console.log("forEach : fin annoncée… trop tôt !");
}
async function avecForOf() {
for (const f of fichiers) {
await attendre(100);
console.log("for...of a traité", f);
}
console.log("for...of : fin, vraiment");
}
async function main() {
await avecForEach();
await attendre(500); // on laisse le forEach finir avant la démo suivante
await avecForOf();
}
main();
Résultat dans la console
forEach : fin annoncée… trop tôt ! forEach a traité a.txt forEach a traité b.txt forEach a traité c.txt for...of a traité a.txt for...of a traité b.txt for...of a traité c.txt for...of : fin, vraiment
Utilisez for…of pour traiter les éléments un par un, ou Promise.all(tableau.map(async …)) pour les traiter en parallèle.
4.2 Autres erreurs classiques
- Oublier
await: la variable contient une promesse, pas la valeur (Promise { <pending> }). awaithors d'une fonctionasync: erreur de syntaxe, sauf au niveau principal d'un module (<script type="module">ou fichier.mjs), où le top-level await est autorisé.- Oublier le
try/catch: une promesse rejetée non gérée produit une erreur Uncaught (in promise) et, dans Node.js, peut arrêter le programme. - Appeler une fonction
asyncsans attendre son résultat: ses erreurs ne remontent pas à l'appelant.
• Une fonction
async renvoie toujours une promesse ; return v = résolue avec v, throw e = rejetée avec e.•
await suspend la fonction, pas le programme : la boucle d'événements continue.• Les erreurs se gèrent avec
try / catch / finally, comme du code synchrone.• Opérations dépendantes →
await en séquence ; indépendantes → await Promise.all. • Jamais d'
await dans forEach: utilisez for…of ou Promise.all + map. 🛠 Activité 5 — La bibliothèque version async / await
Mission : Réécrivez une dernière fois votre scénario de réservation, puis optimisez-le.
Questions pour avancer (répondez dans votre compte rendu, puis appliquez dans votre projet) :
- Écrivez
async function reserverLivre(titre)qui utiliseawaitsur les trois fonctions de l'activité 4. Les fonctions de l'activité 4 doivent-elles être modifiées ? Pourquoi ? - Comparez le nombre de lignes et la lisibilité des trois versions (callbacks, promesses, async/await). Laquelle préférez-vous lire ? Laquelle est la plus facile à déboguer avec des points d'arrêt ?
- Que vaut
reserverLivre("Le Petit Prince")si on l'affiche avecconsole.logsansawait? Comment récupérer le vrai résultat ? - Ajoutez un message « Chargement… » au début et « Terminé » à la fin, affiché même en cas d'erreur. Quel bloc utilisez-vous ?
- Écrivez
reserverPlusieurs(titres)en version séquentielle puis parallèle, et mesurez le temps avecDate.now(). Quel est le gain pour 5 livres ? Dans quel cas la version séquentielle serait-elle quand même obligatoire ? - Votre collègue écrit
titres.forEach(async t => await reserverLivre(t)); console.log("Tout est réservé");. Expliquez-lui le bug et proposez deux corrections. - Dans un fichier
.mjs, essayez d'écrireawait reserverLivre("Candide")directement, hors fonction. Cela fonctionne-t-il ? Et dans un fichier.jsclassique ?
Je vérifie / je rends :
- ☐ Le fichier
bibliotheque-async.js. - ☐ Le tableau comparatif des trois versions et vos mesures de temps.
← 18.4 — Les promesses (Promise, then, catch, Promise.all)TP 18 : Simuler des traitements asynchrones →