`await` dans `forEach()`: pourquoi mes données ne sont-elles pas chargées avant le rendu?

Pour toutes les discussions javascript, jQuery et autres frameworks
Répondre
lucassinner
Messages : 3
Enregistré le : 15 juil. 2025, 13:08

`await` dans `forEach()`: pourquoi mes données ne sont-elles pas chargées avant le rendu?

Message par lucassinner » 11 juil. 2026, 10:05

Bonjour à tous, je travaille actuellement sur une application interne de gestion des commandes en Vue 3. Sur la page de détail, je dois récupérer les informations de chaque client à partir de son `customerId` avant d'afficher le tableau. Les requêtes HTTP aboutissent toutes correctement (200 OK) FNF, mais au moment où le composant est rendu, l'objet `customers` est encore vide. J'utilise actuellement le code ci-dessous:

Code : Tout sélectionner

const customers = {};

orders.forEach(async (order) => {
    const response = await fetch(`/api/customers/${order.customerId}`);
    customers[order.customerId] = await response.json();
});

renderOrders(orders, customers);
En plaçant un point d'arrêt, je vois bien que les réponses arrivent et que les données sont correctes, mais `renderOrders()` est appelé avant la fin de toutes les requêtes. J'ai repris ce module d'un ancien développeur, donc j'essaie de corriger le problème sans tout réécrire. Est-ce que le problème vient de `forEach()` avec `async/await`? Quelle serait la meilleure façon d'attendre que toutes les requêtes soient terminées avant d'appeler `renderOrders()`? Merci d'avance pour vos conseils.

JulienR84
Messages : 40
Enregistré le : 16 sept. 2025, 16:14

Re: `await` dans `forEach()`: pourquoi mes données ne sont-elles pas chargées avant le rendu?

Message par JulienR84 » 25 juil. 2026, 15:42

Hello
Oui, le problème vient bien de forEach() avec async/await. forEach() n'attend pas les promesses retournées par sa callback, il lance toutes les itérations de façon quasi synchrone et continue immédiatement, sans se soucier qu'elles soient async. Résultat : renderOrders() s'exécute avant que les fetch() soient terminés.
La solution la plus simple serait de remplacer forEach() par Promise.all() avec map() :

Code : Tout sélectionner

const customers = {};

await Promise.all(
  orders.map(async (order) => {
    const response = await fetch(`/api/customers/${order.customerId}`);
    customers[order.customerId] = await response.json();
  })
);

renderOrders(orders, customers);

// Promise.all() attend que toutes les promesses soient résolues avant de continuer, contrairement à forEach().
Quelques points à vérifier en plus :
  • La fonction englobante doit elle-même être async pour pouvoir utiliser ce await en haut niveau.
  • Si un des fetch() échoue, Promise.all() rejette immédiatement dès la première erreur. Si tu veux récupérer les clients même en cas d'échec partiel, utilise Promise.allSettled() à la place et gère les résultats individuellement.
  • Attention aux doublons de customerId dans orders : ici ça ne pose pas de problème (on écrase juste la même clé), mais si tu veux optimiser, pense à dédupliquer les IDs avant de lancer les requêtes.

Répondre