À propos de ce cours
Chapitre 18 — Travaux pratiques · TP 18 : Simuler des traitements asynchrones
• mettre en œuvre les callbacks, les promesses et
async/await sur un même problème ;• mesurer l'effet de l'exécution séquentielle et parallèle ;
• gérer les erreurs, les délais maximaux et les nouvelles tentatives ;
• relier un traitement asynchrone à une interface web.
Présentation
Le Café Async veut simuler le traitement de ses commandes. Chaque commande passe par quatre étapes : prendre la commande, préparer la boisson, chauffer la pâtisserie, servir. Chaque étape dure un certain temps et peut échouer au hasard (machine en panne, rupture de stock…).
Vous allez écrire ce traitement trois fois (callbacks, promesses, async/await), puis l'améliorer. Les questions vous guident : à vous de trouver comment les résoudre. Aucune solution n'est donnée.

Figure 1 — Les étapes d'une commande.
Matériel
⬇ Télécharger les fichiers de départ du TP (tp18.js)
- Node.js (commande
node fichier.js) ou la console d'un navigateur (F12). - Le fichier de départ ci-dessous, à enregistrer sous
tp18.js. Ne modifiez pas la fonctionsimulerTraitement.
tp18.js — fichier de départ
// =====================================================================
// TP 18 — Café Async : fichier de départ
// Exécution : node tp18_depart.js (ou copier dans la console du navigateur)
// =====================================================================
// Réglages : modifiez-les pour vos tests
const TAUX_ECHEC = 0.2; // 20 % de chances qu'une étape échoue (0 = jamais)
// ---------------------------------------------------------------------
// OUTIL FOURNI (ne pas modifier) : simule un traitement asynchrone.
// - nom : texte affiché
// - duree : durée en millisecondes
// - tauxEchec : probabilité d'échec, entre 0 et 1
// - callback : appelé à la fin avec (erreur, nom) ← convention error-first
// ---------------------------------------------------------------------
function simulerTraitement(nom, duree, tauxEchec, callback) {
console.log(`⏳ ${nom}…`);
setTimeout(() => {
if (Math.random() < tauxEchec) {
callback(new Error(`${nom} a échoué`));
} else {
console.log(`✅ ${nom} (${duree} ms)`);
callback(null, nom);
}
}, duree);
}
// Les étapes d'une commande et leur durée
const ETAPES = {
commande: { nom: "Prendre la commande", duree: 500 },
boisson: { nom: "Préparer la boisson", duree: 1500 },
patisserie: { nom: "Chauffer la pâtisserie", duree: 1000 },
service: { nom: "Servir le client", duree: 300 },
};
// =====================================================================
// PARTIE 1 — Version callbacks
// Écrivez servirAvecCallbacks(client, callbackFinal)
// =====================================================================
// =====================================================================
// PARTIE 2 — Version promesses
// Écrivez simulerTraitementP(nom, duree, tauxEchec) puis servirAvecPromesses(client)
// =====================================================================
// =====================================================================
// PARTIE 3 — Version async / await
// Écrivez async function servir(client)
// =====================================================================
// =====================================================================
// Lancement : décommentez la version que vous testez
// =====================================================================
// servirAvecCallbacks("Sami", (err, ticket) => console.log(err ? err.message : ticket));
// servirAvecPromesses("Sami").then(console.log).catch((e) => console.log(e.message));
// servir("Sami").then(console.log);
Pendant la mise au point, mettez
TAUX_ECHEC = 0 pour que tout réussisse. Remettez ensuite 0.2, ou même 1, pour tester vos gestions d'erreur.🛠 TP · Partie 1 — Version callbacks
Mission : Écrivez servirAvecCallbacks(client, callbackFinal) qui enchaîne les quatre étapes l'une après l'autre avec simulerTraitement, puis appelle callbackFinal(null, ticket). Le ticket est une chaîne du type « Commande de Sami servie en 3.3 s ».
Questions pour avancer (répondez dans votre compte rendu, puis appliquez dans votre projet) :
- Quels sont les quatre appels à
simulerTraitement? Dans quel ordre doivent-ils s'imbriquer ? - Comment mesurer la durée totale ? Où enregistrez-vous l'heure de départ, et où calculez-vous la différence ?
- Si une étape échoue, la commande s'arrête et
callbackFinalreçoit l'erreur. Combien de fois devez-vous écrire ce test ? Que se passe-t-il si vous en oubliez un ? - Avec
TAUX_ECHEC = 0, quelle durée totale obtenez-vous ? Retrouvez-la à partir du tableauETAPES. - Lancez trois commandes (Sami, Lina, Omar) à la suite dans le code, sans attendre. Les messages se mélangent-ils ? Pourquoi les trois commandes se terminent-elles presque en même temps ?
Je vérifie / je rends :
- ☐ La fonction fonctionne, avec et sans erreurs.
- ☐ Une capture de la console pour trois commandes.
🛠 TP · Partie 2 — Version promesses
Mission : Écrivez simulerTraitementP(nom, duree, tauxEchec) qui renvoie une promesse en réutilisant simulerTraitement, puis servirAvecPromesses(client) qui renvoie une promesse du ticket.
Questions pour avancer (répondez dans votre compte rendu, puis appliquez dans votre projet) :
- À l'intérieur de
new Promise((resolve, reject) => …), quel callback passez-vous àsimulerTraitement? Quand appelez-vousresolve, quand appelez-vousreject? - Enchaînez les quatre étapes avec
then. Où placez-vous l'uniquecatch? Faut-il le mettre dansservirAvecPromessesou chez l'appelant ? Justifiez. - Comment transmettre l'heure de départ jusqu'au dernier
then, qui fabrique le ticket ? - Ajoutez un
finallyqui affiche « — fin du traitement de Sami — ». S'affiche-t-il aussi en cas d'erreur ? - Comparez avec la partie 1 : combien de niveaux d'indentation avez-vous gagnés ? Combien de tests d'erreur avez-vous supprimés ?
Je vérifie / je rends :
- ☐
servirAvecPromesses("Sami").then(console.log).catch(…)fonctionne.
🛠 TP · Partie 3 — Version async / await
Mission : Écrivez async function servir(client) qui renvoie un objet ticket : { client, statut: "servi" | "annulé", duree, erreur? }. La fonction ne doit jamais rejeter : en cas d'échec, elle renvoie un ticket « annulé ».
Questions pour avancer (répondez dans votre compte rendu, puis appliquez dans votre projet) :
- Quelle fonction de la partie 2 réutilisez-vous avec
await? - Où placez-vous
tryetcatchpour transformer une erreur en ticket « annulé » ? - Pourquoi est-il pratique, pour la suite du TP, que
servirne rejette jamais ? - Écrivez
async function main()qui sert Sami, puis Lina, puis Omar, l'un après l'autre. Quelle est la durée totale ? Pourquoi est-elle différente de la question 5 de la partie 1 ?
Je vérifie / je rends :
- ☐ Un affichage clair des trois tickets, par exemple avec
console.table.
🛠 TP · Partie 4 — Gagner du temps : le parallélisme
Mission : La boisson et la pâtisserie sont préparées par deux personnes différentes : elles peuvent se faire en même temps. Modifiez servir en conséquence, puis servez plusieurs clients en parallèle.
Questions pour avancer (répondez dans votre compte rendu, puis appliquez dans votre projet) :
- Quelles étapes dépendent l'une de l'autre, et lesquelles sont indépendantes ? Dessinez le graphe des dépendances.
- Quelle méthode utilisez-vous pour attendre la boisson et la pâtisserie ensemble ? Quelle durée obtenez-vous maintenant pour une commande ? Faites le calcul avant de mesurer.
- Si la pâtisserie échoue, la boisson doit-elle être jetée ? Quelle méthode,
allouallSettled, correspond à la règle « on sert quand même la boisson seule » ? Implémentez cette règle. - Servez 5 clients en parallèle avec
Promise.all(clients.map(servir)). PourquoiPromise.allne rejette-t-il jamais ici ? - Le café n'a en réalité qu'une machine à boissons. Votre simulation parallèle est-elle encore réaliste ? Quelle idée proposeriez-vous (sans forcément la coder) pour limiter à une boisson à la fois ?
Je vérifie / je rends :
- ☐ Mesures de durée avant et après parallélisation, pour 1 et pour 5 clients.
🛠 TP · Partie 5 — Délai maximal et nouvelles tentatives
Mission : Un client n'attend pas plus de 3 secondes, et une étape qui échoue peut être retentée.
Questions pour avancer (répondez dans votre compte rendu, puis appliquez dans votre projet) :
- Écrivez
avecDelaiMax(promesse, ms)qui rejette avec « Délai dépassé » si la promesse n'est pas réglée à temps. Quelle méthode statique utilisez-vous ? Que devient l'opération lente quand le délai est dépassé : est-elle vraiment arrêtée ? - Testez-la en mettant la préparation de la boisson à 4000 ms. Que contient le ticket ?
- Écrivez
async function reessayer(fonction, nbEssais)qui appellefonction()(qui renvoie une promesse) et recommence en cas d'échec, jusqu'ànbEssaisfois. Pourquoi faut-il passer une fonction et non directement une promesse ? - Ajoutez une pause croissante entre deux essais (200 ms, puis 400 ms, puis 800 ms). Comment s'appelle cette stratégie ? Pourquoi est-elle utilisée par les vrais services en ligne ?
- Avec
TAUX_ECHEC = 0.5et 3 essais par étape, servez 20 clients. Combien sont servis ? Comparez avec la même expérience sans nouvelles tentatives.
Je vérifie / je rends :
- ☐ Les fonctions
avecDelaiMaxetreessayer, testées. - ☐ Le bilan de l'expérience à 20 clients.
🛠 TP · Partie 6 — Bonus : l'interface du Café Async
Mission : Créez une page index.html avec un champ « nom du client », un bouton « Commander » et une liste des commandes. Chaque commande affiche ses étapes en direct (⏳ puis ✅ ou ❌).
Questions pour avancer (répondez dans votre compte rendu, puis appliquez dans votre projet) :
- Comment remplacer les
console.logdesimulerTraitementpar un affichage dans la page, sans modifier la fonction fournie ? (indice : copiez-la sous un autre nom, ou passez une fonction d'affichage en paramètre de vos propres fonctions) - Pendant qu'une commande est en préparation, l'utilisateur peut-il en lancer une autre ? Qu'est-ce qui le permet, d'après la leçon 2 ?
- Comment désactiver le bouton pendant le traitement, et le réactiver même en cas d'erreur ?
- Ajoutez une barre de progression (
<progress>) qui avance à chaque étape terminée. Où mettez-vous à jour sa valeur ? - Ajoutez un bouton « Commander pour 5 clients » et un compteur « servis / annulés » mis à jour à la fin de toutes les commandes.
Je vérifie / je rends :
- ☐ La page fonctionnelle (capture ou vidéo courte).
Grille d'évaluation indicative
| Critère | Points |
|---|---|
| Partie 1 — callbacks : enchaînement et erreurs correctes | 3 |
Partie 2 — promisification et chaîne plate avec un seul catch | 3 |
Partie 3 — async/await, try/catch, tickets | 3 |
| Partie 4 — parallélisme justifié et mesuré | 4 |
| Partie 5 — délai maximal et nouvelles tentatives | 4 |
| Qualité du code (noms, commentaires, aucune variable globale inutile) | 2 |
| Compte rendu : réponses aux questions et mesures | 1 |
| Total (bonus : jusqu'à +3 pour la partie 6) | 20 |
← 18.5 — async et await