> Maîtriser l'asynchrone en JavaScript : promesses (then/catch/finally), async/await, gestion d'erreurs, Promise.all et race, fetch et les pièges de l'await en boucle.

*Source : https://coder-studio.com/tutoriels/async-await-promesses-js/*

---

[// Web](https://coder-studio.com/tutoriels/)

# async/await et les promesses en JavaScript

Par **Kévin Papot** · publié le 5 février 2026

Dès qu’un programme JavaScript doit attendre — une requête réseau, la lecture d’un fichier, un délai — il devient **asynchrone**. Le couple **async/await** est aujourd’hui la façon la plus lisible d’écrire ce type de code, mais il repose entièrement sur les promesses. Comprendre les deux, et savoir passer de l’un à l’autre, est indispensable pour tout développeur web. Ce guide déroule chaque opération : créer une promesse, la consommer, gérer les erreurs, paralléliser, appeler une API et éviter les pièges classiques.

## Pourquoi l’asynchrone ?

JavaScript est mono-thread : il n’exécute qu’une chose à la fois. Si une opération lente bloquait le fil d’exécution, toute la page se figerait. L’asynchrone permet de lancer une tâche longue, de continuer le reste du code, et de traiter le résultat quand il arrive.

```
console.log("1");
setTimeout(() => console.log("2 (plus tard)"), 0);
console.log("3");
// Affiche : 1, 3, 2 — le setTimeout est différé
```

## Qu’est-ce qu’une promesse ?

Une **promesse** (`Promise`) représente une valeur qui n’est pas encore disponible. Elle a trois états : _pending_ (en attente), _fulfilled_ (résolue) ou _rejected_ (rejetée). On la crée avec un exécuteur recevant deux fonctions, `resolve` et `reject`.

```
const promesse = new Promise((resolve, reject) => {
  const succes = true;
  setTimeout(() => {
    if (succes) {
      resolve("Données reçues");
    } else {
      reject(new Error("Échec du chargement"));
    }
  }, 1000);
});
```

## Consommer une promesse : then, catch, finally

On réagit au résultat avec `.then()` (succès), `.catch()` (erreur) et `.finally()` (toujours exécuté).

```
promesse
  .then((valeur) => {
    console.log("Succès :", valeur);
  })
  .catch((erreur) => {
    console.error("Erreur :", erreur.message);
  })
  .finally(() => {
    console.log("Terminé, quel que soit le résultat");
  });
```

`.then()` renvoie elle-même une promesse, ce qui permet de **chaîner** des opérations séquentielles. La valeur retournée dans un `.then` est transmise au suivant.

```
recupererUser(1)
  .then((user) => recupererCommandes(user.id)) // renvoie une promesse
  .then((commandes) => console.log(commandes.length))
  .catch((err) => console.error(err));
```

Un seul `.catch()` en fin de chaîne intercepte l’erreur de n’importe quel maillon.

## La syntaxe async/await

`async/await` est du sucre syntaxique sur les promesses. Une fonction `async` renvoie toujours une promesse, et `await` met en pause l’exécution jusqu’à ce que la promesse soit résolue — sans bloquer le reste du programme.

```
async function afficherUser() {
  const user = await recupererUser(1);       // attend la résolution
  const commandes = await recupererCommandes(user.id);
  console.log(commandes.length);
}
```

Le même enchaînement qu’avec `.then()`, mais qui se lit comme du code synchrone, de haut en bas. C’est là tout l’intérêt. `await` ne s’utilise qu’à l’intérieur d’une fonction `async` (ou au niveau supérieur d’un module).

## Gérer les erreurs avec try/catch

Avec async/await, on remplace `.catch()` par un bloc `try/catch` classique, ce qui unifie la gestion des erreurs synchrones et asynchrones.

```
async function chargerDonnees() {
  try {
    const user = await recupererUser(1);
    const commandes = await recupererCommandes(user.id);
    return commandes;
  } catch (erreur) {
    console.error("Impossible de charger :", erreur.message);
    return []; // valeur de repli
  } finally {
    console.log("Fin de chargement");
  }
}
```

## Paralléliser avec Promise.all

`await` en série attend chaque promesse l’une après l’autre. Quand les opérations sont **indépendantes**, lancez-les en parallèle avec `Promise.all`, qui attend que toutes soient résolues.

```
async function chargerTout() {
  // En parallèle : les trois partent en même temps
  const [users, produits, stats] = await Promise.all([
    fetch("/api/users").then(r => r.json()),
    fetch("/api/produits").then(r => r.json()),
    fetch("/api/stats").then(r => r.json()),
  ]);
  return { users, produits, stats };
}
```

Attention : `Promise.all` rejette dès qu’**une** promesse échoue. Si vous voulez le résultat de chacune, succès ou échec, utilisez `Promise.allSettled`.

```
const resultats = await Promise.allSettled([
  recupererUser(1),
  recupererUser(999), // échoue peut-être
]);
// [{ status: "fulfilled", value: ... }, { status: "rejected", reason: ... }]
```

## Promise.race et Promise.any

`Promise.race` renvoie le résultat de la **première** promesse terminée, qu’elle réussisse ou échoue. Pratique pour imposer un délai maximal.

```
function timeout(ms) {
  return new Promise((_, reject) =>
    setTimeout(() => reject(new Error("Trop long")), ms)
  );
}

async function avecDelai() {
  // Échoue si la requête dépasse 3 secondes
  return Promise.race([fetch("/api/lent"), timeout(3000)]);
}
```

`Promise.any`, lui, renvoie la première promesse **réussie** et ignore les échecs tant qu’il en reste une qui peut aboutir.

## Récupérer des données avec fetch

`fetch` est l’API standard pour les requêtes HTTP, et elle est fondée sur les promesses. Point important : `fetch` ne rejette **pas** sur une erreur HTTP (404, 500) ; il faut vérifier `response.ok` soi-même.

```
async function getUser(id) {
  const reponse = await fetch(`https://api.exemple.com/users/${id}`);

  if (!reponse.ok) {
    throw new Error(`HTTP ${reponse.status}`);
  }

  return reponse.json(); // renvoie une promesse
}

// POST avec un corps JSON
async function creerUser(data) {
  const reponse = await fetch("https://api.exemple.com/users", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data),
  });
  return reponse.json();
}
```

Pour aller plus loin sur les verbes HTTP et les codes de statut, consultez notre [guide des API REST](https://coder-studio.com/tutoriels/api-rest-guide/).

## Le piège de l’await en boucle

C’est l’erreur de performance la plus fréquente. Un `await` dans une boucle `for` traite les éléments **un par un**, en série, ce qui est lent quand les opérations sont indépendantes.

```
// Lent : chaque requête attend la précédente
async function chargerLent(ids) {
  const resultats = [];
  for (const id of ids) {
    const user = await getUser(id); // séquentiel
    resultats.push(user);
  }
  return resultats;
}
```

La bonne approche : lancer toutes les requêtes en parallèle avec `map`, puis attendre l’ensemble avec `Promise.all`.

```
// Rapide : toutes les requêtes partent en même temps
async function chargerRapide(ids) {
  const promesses = ids.map((id) => getUser(id));
  return Promise.all(promesses);
}
```

Ce patron combine les [méthodes de tableau](https://coder-studio.com/tutoriels/tableaux-javascript-methodes/) et les promesses. Réservez l’`await` en boucle aux cas où l’ordre compte réellement (par exemple des écritures dépendantes).

## Autres pièges courants

Quelques erreurs à connaître pour ne pas se faire piéger.

```
// 1. Oublier await : on manipule une promesse, pas la valeur
async function bug() {
  const user = getUser(1);        // Promise, pas l'objet
  console.log(user.nom);          // undefined
}

// 2. Oublier return dans une chaîne .then
promesse.then((v) => {
  traiter(v); // sans return, le .then suivant reçoit undefined
});

// 3. Avaler les erreurs silencieusement
async function silencieux() {
  try {
    await risque();
  } catch {
    // ne rien faire ici masque le vrai problème
  }
}
```

## À retenir

Une promesse représente une valeur future ; `.then/.catch/.finally` la consomment, et `async/await` la rend lisible comme du code synchrone. Gérez les erreurs avec `try/catch`, parallélisez les tâches indépendantes avec `Promise.all` plutôt que d’enchaîner les `await`, et vérifiez toujours `response.ok` après un `fetch`. Le réflexe le plus rentable : dès que vous écrivez `await` dans une boucle, demandez-vous si `Promise.all` ne ferait pas le travail plus vite.

## À lire ensuite

-   [Les tableaux en JavaScript : map, filter, reduce et toutes les méthodes](https://coder-studio.com/tutoriels/tableaux-javascript-methodes/)
-   [Le guide des API REST : principes, méthodes et bonnes pratiques](https://coder-studio.com/tutoriels/api-rest-guide/)
-   [Fonctions fléchées et closures en JavaScript](https://coder-studio.com/tutoriels/fonctions-flechees-closures-js/)
