Une requête réseau met de quelques dizaines de millisecondes à plusieurs secondes à répondre. Sans await, la suite du travail se décrit dans une fonction confiée à .then(), et le code se lit à l'envers dès trois étapes.
await remet les instructions dans l'ordre. La ligne qui suit ne s'exécute qu'une fois le résultat arrivé, comme si l'attente était instantanée.
Définition
await suspend l'exécution de la fonction qui le contient jusqu'à ce que la Promise placée à sa droite soit résolue, puis reprend avec la valeur obtenue.
async function chargeClient(id) {
const reponse = await fetch('/api/clients/' + id);
const client = await reponse.json();
return client.nom;
}Deux attentes, deux lignes, dans l'ordre de lecture. Sans le mot-clé, reponse ne contiendrait pas une réponse mais une promesse, et la ligne suivante échouerait sur une méthode introuvable.
await ne fige pas le navigateur. Il met en pause la fonction en cours, pas la page : les animations continuent, les clics sont reçus, le reste du programme s'exécute. C'est la différence entre attendre et bloquer.
Où il a le droit d'apparaître
Deux emplacements, pas un de plus : dans le corps d'une fonction async, et au niveau supérieur d'un module. Partout ailleurs, le fichier refuse de se charger.
// dans une fonction async
async function main() {
const donnees = await charge();
}
// au niveau supérieur d'un module
const donnees = await charge();Placé devant une valeur ordinaire, await la renvoie telle quelle : inutile de vérifier si ce que vous attendez est bien une promesse.
En série ou en parallèle
C'est l'erreur qui coûte le plus cher, et elle ne se voit pas à la lecture. Deux await consécutifs attendent l'un après l'autre, même si les deux opérations sont indépendantes.
const attente = (ms, v) => new Promise(r => setTimeout(() => r(v), ms));
// en série : environ 120 ms
const a = await attente(60, 'a');
const b = await attente(60, 'b');
// en parallèle : environ 60 ms
const [x, y] = await Promise.all([attente(60, 'x'), attente(60, 'y')]);La règle : enchaînez les await quand la seconde opération a besoin du résultat de la première, lancez-les ensemble sinon. Sur une page qui charge cinq ressources, la différence se compte en secondes.
Gérer l'échec
Une promesse rejetée transforme la ligne await en erreur ordinaire, qui se rattrape donc avec try et catch.
try {
const client = await chargeClient(7);
afficher(client);
} catch (erreur) {
console.error('Chargement impossible :', erreur.message);
}Sans ce filet, l'échec remonte en rejet non intercepté, visible dans la console mais invisible pour l'utilisateur, qui reste devant un écran vide.
Questions fréquentes
Que se passe-t-il si j'oublie le mot-clé ?
La variable reçoit l'objet promesse au lieu de la valeur attendue. Le symptôme habituel est un affichage qui indique [object Promise], ou une propriété qui vaut undefined alors que les données sont bien arrivées. Dès que vous voyez ce mot dans une valeur, cherchez le await manquant.
Peut-on attendre à l'intérieur d'une boucle ?
Oui, et c'est même l'usage courant dans une boucle of, par exemple pour traiter des éléments l'un après l'autre sans saturer un serveur. Attention en revanche avec Array.forEach(), qui ne patiente pas : la boucle se termine avant les traitements et le résultat semble vide.
await ou .then(), lequel choisir ?
Les deux font le même travail, et rien n'interdit de les mélanger. await l'emporte dès qu'il y a plusieurs étapes ou une gestion d'erreur, parce que le code garde la forme d'une lecture linéaire. .then() reste pratique pour un traitement unique posé à la volée sur une promesse.