1.2 · Asynchrone : callbacks, Promises, async/await

Niveau 1 · JavaScript & bases Node

1.2Asynchrone : callbacks, Promises, async/await

Objectif : comprendre et manipuler l'asynchrone sous ses trois formes (callbacks, Promises, async/await), et privilégier async/await — le cap central de Node.
Temps estimé : 13 min · lecture autonome · Si vous n'avez que 5 min : lisez « L'essentiel en 30s » + le schéma.

L'essentiel en 30 secondes

  • L'asynchrone = « quand ce sera prêt » : les opérations lentes se lancent et leur résultat arrive plus tard — on ne peut pas le lire sur la ligne suivante.
  • Callbacks → callback hell : la convention error-first (erreur en 1er argument) fonctionne, mais les callbacks dépendants s'imbriquent en pyramide illisible.
  • async/await à privilégier : await attend sans bloquer, le code se lit comme du synchrone, erreurs via try/catch — construit sur les Promises.

Mini-cas filé — Salim attend ses fichiers à Alger

Salim doit lire un fichier de configuration, puis interroger une base avec son contenu, puis appeler une API : il écrit trois callbacks imbriqués et se perd dans l'indentation — pire, son console.log affiche undefined car il lit le résultat avant qu'il arrive. Il réécrit le tout en async/await avec try/catch : trois lignes await lisibles dans l'ordre, et l'erreur gérée à un seul endroit. Le bug de l'undefined disparaît avec l'ancien modèle mental.

Suite du cas 1.1 — Salim passe du langage au cœur de Node : l'asynchrone.

1. Des callbacks au callback hell

L'asynchrone est LE concept central de Node : les opérations lentes (lire un fichier, interroger une base, appeler une API) se lancent et leur résultat arrive plus tard. Le mécanisme historique est le callback : une fonction passée en argument, rappelée à la fin de l'opération — avec la convention error-first (erreur en premier argument, null si tout va bien). Enchaîner des opérations dépendantes mène au callback hell : une pyramide illisible, difficile à gérer surtout pour les erreurs.

Salim écrit fs.readFile('config.txt', (err, data) => ...) et repère la convention error-first : tester err d'abord, exploiter data ensuite — jamais l'inverse.

2. Les Promises : la valeur future chaînée

Une Promise représente une valeur future — le résultat d'une opération pas encore terminée. Trois états : pending (en attente), fulfilled (succès, une valeur), rejected (erreur). On réagit avec .then() (succès) et .catch() (erreur), et les Promises se chaînent au lieu de s'imbriquer — bien plus lisible que le callback hell.

Salim réécrit sa lecture de fichier en fs.promises.readFile(...).then().catch() : la chaîne remplace la pyramide et l'erreur atterrit dans un seul .catch().

3. async/await : la lisibilité (à privilégier)

La vraie révolution de lisibilité est async/await : dans une fonction async, await attend le résultat sans bloquer (sucre syntaxique sur les Promises) et le code asynchrone se lit comme du synchrone, ligne après ligne, avec un try/catch classique pour les erreurs. C'est le style dominant et recommandé : vous rencontrerez les trois formes dans le code existant, mais vous écrirez principalement en async/await.

Salim termine avec const data = await fs.promises.readFile(...) dans un try/catch : trois opérations en trois lignes ordonnées — son code asynchrone se lit enfin comme une recette.

Erreur d'interprétation fréquente : « await bloque le programme comme un sleep » ou « on peut lire le résultat sur la ligne suivant l'appel ». Non. await suspend seulement la fonction async en attendant la Promise, sans bloquer la boucle d'événements — les autres requêtes continuent d'être traitées. Et le résultat d'une opération asynchrone n'existe pas encore sur la ligne suivante : il faut le consommer dans le callback, le .then() ou après un await.
L'évolution de l'asynchrone Vers la lisibilité Callbacks error-first,risque de callback hellPromises Valeur future,chaînage .then/.catchasync/await Se lit comme dusynchrone, try/catch
Vers la lisibilité
Version texte du schéma (SEO / lecteurs d'écran / traduction) : 1) Lancer, pas attendre : Salim lance la lecture du fichier et donne un callback « quand ce sera prêt » (error-first) au lieu de lire le résultat sur la ligne suivante. 2) Chaîner : il remplace les callbacks imbriqués par des Promises en .then().catch() — fini la pyramide. 3) Aplatir : il passe en async/await dans un try/catch, trois opérations en trois lignes lisibles. Leçon : distinguer « lancer » et « obtenir le résultat » est le modèle mental qui débloque tout Node.

La pyramide infernale (ne faites jamais ça)

« J'enchaîne six callbacks imbriqués, je m'y retrouve encore… au 3e niveau. »
Verdict : au 4e niveau, même l'auteur ne s'y retrouve plus — et la gestion d'erreurs est éparpillée partout.
« Mon console.log affiche undefined, le fichier doit être vide. »
Verdict : le fichier est plein, c'est votre lecture qui arrive trop tôt — le résultat n'existe pas encore sur la ligne suivante.

Moralité : imbriquer, c'est s'enterrer — aplatir avec await, c'est respirer.

🔎 Exemple concret — 🔎 Exemple concret — Le même code en async/await

Lisible, non-bloquant, erreurs gérées — le style à écrire.

const fs = require("fs");
async function lire() {
  try {
    const data = await fs.promises.readFile("f.txt", "utf8");
    console.log(data);
  } catch (err) {
    console.error("Echec :", err.message);
  }
}
lire();

Lecture : await attend le contenu sans bloquer ; en cas d'échec, le catch affiche le message.

Leçon : Promise.all pour lancer plusieurs opérations indépendantes en parallèle.

Vocabulaire de la section

Callback
Fonction passée en argument, appelée quand une opération asynchrone se termine. Convention Node error-first : premier argument = erreur (null si OK), puis le résultat.

Exemple simple : Le (err, data) => ... de la lecture de fichier de Salim.

Ce que ce n'est pas : une fonction appelée immédiatement avec un résultat déjà prêt.

Réflexe : tester err d'abord, exploiter le résultat ensuite.

Callback hell
Imbrication illisible de callbacks quand on enchaîne des opérations asynchrones dépendantes ; problème résolu par les Promises et async/await.

Exemple simple : La pyramide à trois niveaux du premier script de Salim.

Ce que ce n'est pas : trois await alignés lisiblement dans une fonction async.

Réflexe : dès que ça s'imbrique, passer aux Promises.

Promise
Objet représentant une valeur future. Trois états : pending, fulfilled (succès), rejected (erreur). Réactions via .then() et .catch().

Exemple simple : La promesse renvoyée par fs.promises.readFile chez Salim.

Ce que ce n'est pas : le contenu du fichier disponible sur la ligne suivante.

Réflexe : .then pour le succès, .catch pour l'erreur.

async/await
Syntaxe moderne construite sur les Promises : await attend le résultat sans bloquer ; le code asynchrone se lit comme du synchrone. Erreurs via try/catch.

Exemple simple : Les trois await ordonnés du script final de Salim.

Ce que ce n'est pas : un sleep qui bloquerait toute l'application.

Réflexe : écrire en async/await par défaut.

error-first / try-catch
Gestion d'erreurs selon la forme : erreur en premier argument des callbacks, .catch() pour les Promises, try/catch autour des await.

Exemple simple : Le try/catch unique qui sécurise les trois opérations de Salim.

Ce que ce n'est pas : ignorer l'erreur et laisser l'application planter en silence.

Réflexe : toujours un chemin d'erreur explicite.

En pratique — En pratique — Maîtriser l'asynchrone

  1. Écrivez une opération asynchrone avec un callback (ex. fs.readFile) et repérez la convention error-first (err, data).
  2. Enchaînez deux opérations dépendantes avec des callbacks imbriqués : constatez le début du callback hell.
  3. Réécrivez avec des Promises et le chaînage .then().then().catch() : observez la meilleure lisibilité.
  4. Réécrivez enfin en async/await (fonction async, await devant les opérations, try/catch pour les erreurs) : le code se lit comme du synchrone.
Vous comprenez et manipulez l'asynchrone sous ses trois formes (callbacks, Promises, async/await), et privilégiez async/await pour un code lisible — le cap central de Node.

Script prêt à dire — expliquer l'asynchrone à un collègue (1 min)

« En Node, une opération lente se lance mais son résultat arrive plus tard : on ne le lit jamais sur la ligne suivante. On dit +quand ce sera prêt, fais ceci+ — avec un callback, un .then() ou un await. C'est pour ça qu'on écrit en async/await : le code attend sans bloquer et se lit dans l'ordre. »

À dire devant le bug classique du console.log qui affiche undefined.

Modèle copier-coller — lecture de fichier async/await

const fs = require("fs");
async function lire(nom) {
  try {
    const data = await fs.promises.readFile(nom, "utf8");
    console.log(data);
    return data;
  } catch (err) {
    console.error("Echec :", err.message);
    return null;
  }
}
lire("f.txt");

Opérations dépendantes

Lire un fichier, puis interroger avec son contenu : enchaîner les await dans l'ordre dans un seul try/catch — comme Salim avec config → base → API.

Opérations indépendantes

Plusieurs lectures sans lien entre elles : les lancer ensemble avec Promise.all pour aller vite au lieu d'attendre chacune son tour.

Vieux code en callbacks

Face à une API error-first existante : la comprendre et l'utiliser telle quelle pour lire, mais écrire tout le code neuf en async/await.

Erreur silencieuse à Alger

Salim ajoute systématiquement un catch qui affiche err.message : une erreur asynchrone non gérée fait planter ou ment en silence — jamais d'await sans filet.

✓ Bonnes pratiques

  • Distinguer « lancer » et « obtenir ».
  • Écrire en async/await par défaut.
  • Toujours un chemin d'erreur explicite.

✗ Pièges fréquents

  • Lire le résultat ligne suivante.
  • Imbriquer les callbacks dépendants.
  • await sans try/catch.

Points clés à retenir

  • L'ASYNCHRONE est LE concept central de Node : les opérations lentes se lancent et leur résultat arrive PLUS TARD.
  • Progression : CALLBACKS (error-first) → risque de callback hell → PROMISES (chaînage .then/.catch) → ASYNC/AWAIT.
  • Une PROMISE = valeur future (pending/fulfilled/rejected) ; on réagit avec .then() (succès) et .catch() (erreur).
  • ASYNC/AWAIT (à privilégier) : await attend sans bloquer, le code se LIT comme du synchrone, erreurs via try/catch.

Défi 48h — appliquez demain

Prenez le modèle ci-dessus : lisez un vrai fichier avec un callback, réécrivez en Promises, puis en async/await avec try/catch. Comparez les trois versions. 25 minutes suffisent.

Checklist sortie de section
  • Je peux expliquer « lancer » vs « obtenir le résultat ».
  • Je sais quand utiliser callback, Promise ou await.
  • J'ai écrit la même opération sous les trois formes.
Auto-évaluation 1-5 : est-ce que je repère le bug du résultat lu trop tôt ?est-ce que mon code neuf est en async/await avec try/catch ?

Questions fréquentes

Pourquoi l'asynchrone est-il si déroutant au début, et comment vraiment le comprendre ?

Il rompt avec l'intuition « chaque ligne se termine avant la suivante ». Le piège classique : lire le résultat sur la ligne suivant l'appel — on obtient undefined car l'opération n'a pas encore fini. Le modèle mental à adopter : distinguer « lancer » (immédiat) et « obtenir le résultat » (plus tard, via callback, .then() ou await). Pensez « quand ce sera prêt, fais ceci » — comme une commande au restaurant : on ne reste pas planté à la cuisine, on continue et on est servi quand c'est prêt. Une fois ce déclic passé, comme pour Salim, tout Node devient lisible.

Callbacks, Promises ou async/await : lequel utiliser aujourd'hui ?

Vous devez connaître les trois mais écrire en async/await. Callbacks : la forme historique, à comprendre pour lire le code existant et les API classiques (convention error-first) — évitez d'en imbriquer. Promises : le socle moderne (async/await est construit dessus) — à comprendre, et utiles directement pour le parallélisme (Promise.all). async/await : votre style par défaut pour tout code neuf — lisible, erreurs via try/catch. Règle pratique : écrire en await, comprendre les Promises, savoir lire les callbacks.

Vérifiez votre compréhension

Que fait await dans une fonction async ?

Ressources supplémentaires (optionnel, pour aller plus loin)

Examen du niveau 1Questions inédites et durcies pour valider vos acquis