async / await : attendre une réponse sans bloquer la page
Comprenez ce qu’une Promise représente et pourquoi await suspend une fonction sans figer votre application.
Où en êtes-vous avec cette notion ?
Une indication personnelle, enregistrée uniquement dans ce navigateur.
À lire ensuite
Le format café
L’essentiel à comprendre, le temps d’un café.
Envie de creuser ? Un cours plus complet vous attend juste après, à déplier sans quitter cette page.
Ce que vous allez comprendre
Pourquoi la réponse d’une API arrive plus tard, et pourquoi await suspend la suite d’une fonction sans geler l’application.
Une valeur qui n’est pas encore là
La réponse d’une API peut mettre vingt millisecondes ou plusieurs secondes. fetch() ne fait donc pas patienter le programme : il renvoie immédiatement une Promise, c’est-à-dire « une valeur que je n’ai pas encore, mais que je devrais obtenir plus tard ».
fetch("/api/users/42")
│
▼
Promise
│
│ quelques millisecondes…
▼
Réponse
await attend, il ne bloque pas
await se lit ainsi : « pour continuer cette fonction, attends que cette Promise ait produit son résultat ». C’est une suspension locale.
Attendre n’est pas bloquer. await fetch(…) ne gèle pas l’application : seule la suite de la fonction asynchrone est mise en pause. Pendant ce temps, l’environnement continue généralement de traiter les clics, les autres événements et les traitements en attente. C’est précisément ce qui rend l’asynchrone utile sur le Web.
await s’écrit dans une fonction déclarée async. Ce mot-clé annonce que la fonction travaille avec de l’asynchrone, et qu’elle renvoie elle-même une Promise.
Un exemple complet
L’URL est illustrative : cet exemple suppose une API réelle qui répond sur cette adresse.
async function getUser() {
try {
const response = await fetch('/api/users/42');
if (!response.ok) {
throw new Error('Réponse HTTP ' + response.status);
}
const user = await response.json();
return user;
} catch (error) {
console.error('Impossible de récupérer l’utilisateur', error);
}
}
Deux points méritent l’attention. try / catch entoure l’attente pour traiter l’échec au même endroit que le succès. Et fetch() ne rejette pas parce que le serveur répond 404 ou 500 : du point de vue du réseau, ces statuts sont des réponses valides. Le contrôle response.ok reste donc à votre charge.
Fiche mémo
| Élément | À retenir |
|---|---|
| Promise | Une valeur attendue plus tard |
async | Cette fonction travaille avec de l’asynchrone |
await | Suspend la suite de cette fonction |
| Blocage | Non : le reste de l’application continue |
fetch | Ne rejette pas sur un statut 404 ou 500 |
L’idée à emporter : await met en pause une fonction, pas votre application.
Et si on allait plus loin ?
Le café vous a donné les repères. Prenez maintenant le temps de comprendre les mécanismes et de pratiquer, si vous le souhaitez.
Aller plus loinCe qu’await suspend vraiment, et où atterrissent les erreursDévelopper le coursReplier le cours
Ce que vous saurez faire
Lire une fonction async en sachant ce qui est suspendu et ce qui continue, distinguer un échec réseau d’une réponse d’erreur, et placer le catch au bon endroit.
Les exemples se collent dans la console d’un navigateur ou s’exécutent avec node fichier.js (Node.js 18 ou plus récent, où fetch est disponible). Ceux qui appellent /api/users/42 supposent en revanche un serveur qui répond sur cette adresse : sans lui, l’appel échoue.
1. Une Promise est un état, pas un résultat
Une Promise se trouve dans l’un de trois états : en attente, tenue avec une valeur, ou rejetée avec une raison. await ne fabrique pas la valeur, il attend le passage de l’attente vers l’un des deux états finaux.
const promesse = new Promise((resolve) => {
setTimeout(() => resolve('résultat tardif'), 300);
});
console.log(promesse); // Promise en attente
console.log(await promesse); // résultat tardif
Dans la console d’un navigateur, le premier affichage montre une Promise en attente, le second la chaîne, environ trois cents millisecondes plus tard. Ce await au niveau supérieur fonctionne dans la console et dans un module ECMAScript ; dans un fichier .js exécuté par Node.js, placez-le à l’intérieur d’une fonction async.
Référence : Promise.
2. await suspend une fonction, pas le programme
La distinction est facile à vérifier avec de simples minuteurs, sans aucun serveur.
function attendre(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function lente() {
console.log('début de lente');
await attendre(1000);
console.log('fin de lente');
}
lente();
console.log('après l’appel');
setTimeout(() => console.log('minuteur indépendant'), 200);
Résultat attendu : début de lente, puis après l’appel, puis minuteur indépendant vers deux cents millisecondes, puis fin de lente vers une seconde. La preuve est là : pendant l’attente, le reste du code s’est exécuté. Seule la suite de lente était suspendue.
L’inverse mérite attention : un calcul synchrone long, placé avant ou après un await, bloque bel et bien tout le reste. await n’ajoute pas de parallélisme, il organise l’attente.
3. Deux familles d’erreurs, un seul catch
fetch() rejette en cas d’échec réseau : serveur injoignable, connexion coupée, requête annulée. Il ne rejette pas parce que la réponse porte un statut 404 ou 500, puisque de son point de vue la réponse est bien arrivée. Ces deux situations demandent donc deux traitements distincts.
async function getUser(id) {
const response = await fetch('/api/users/' + id); // rejette si le réseau échoue
if (!response.ok) { // 404, 500… à traiter soi-même
throw new Error('Réponse HTTP ' + response.status);
}
return response.json();
}
Une erreur levée dans une fonction async ne se propage pas comme une erreur synchrone : elle transforme la Promise renvoyée en Promise rejetée. Autrement dit, getUser(42) ne plante pas au moment de l’appel ; c’est l’attente de son résultat qui échoue. L’appelant doit donc écrire son propre try / catch, ou attacher un .catch(). Un appel getUser(42); sans rien autour laisse un rejet non géré.
Référence : Utiliser fetch.
Pièges et limites
- Confondre suspension et blocage.
awaitsuspend la fonction courante. Une boucle de calcul d’une seconde, elle, gèle réellement la page. - Oublier le
catchde l’appelant. Une fonctionasyncqui lève renvoie une Promise rejetée. Sanscatchen aval, l’erreur devient un rejet non géré, souvent visible seulement dans la console. - Croire que
fetchsignale les erreurs HTTP. Sansresponse.ok, un corps d’erreur au format HTML sera passé àresponse.json(), et l’échec apparaîtra beaucoup plus loin, sous une forme trompeuse. - Enchaîner des
awaitindépendants. Trois attentes successives s’additionnent alors que les opérations pourraient partir ensemble.
À vous de jouer
Écrivez une fonction lireTitre(url) qui récupère du JSON et renvoie son champ title. Elle doit lever une erreur explicite si le statut n’est pas satisfaisant. Appelez-la ensuite avec une adresse volontairement inexistante de votre propre serveur, et affichez un message lisible dans la console plutôt qu’un rejet non géré. Observez enfin ce qui change si vous retirez le catch de l’appelant.
Correction commentée
async function lireTitre(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Statut inattendu : ' + response.status);
}
const donnees = await response.json();
return donnees.title;
}
lireTitre('/api/articles/introuvable')
.then((titre) => console.log('Titre :', titre))
.catch((error) => console.error('Lecture impossible :', error.message));
Pourquoi c’est la bonne réponse. Le contrôle response.ok transforme une réponse d’erreur, que fetch considère comme un succès, en erreur applicative explicite. Le throw placé dans une fonction async produit une Promise rejetée : voilà pourquoi le catch se met sur l’appel, et non dans la fonction. Sans lui, l’environnement signale un rejet non géré et le message reste illisible. Enfin, await response.json() est nécessaire parce que la lecture du corps est elle aussi asynchrone : le corps arrive en flux, pas d’un seul bloc.
Vous pouvez aussi vous arrêter ici. L’approfondissement est facultatif.
Les repères Cours Café
Pour aller à la source
Documentation de référence. Vérification éditoriale encore à effectuer.
Gardez une trace de cette idée.
Favoris, notes et progression seront disponibles après connexion du stockage distant.