JavaScript : L'asynchrone
Pourquoi JavaScript est asynchrone, et comment le gérer : callbacks, promesses, async / await et fetch pour appeler une API sans bloquer la page.
JavaScript : L'asynchrone
Certaines opérations prennent du temps : appeler une API, lire un fichier, attendre un délai. Le problème, c'est que JavaScript est monothread : il n'exécute qu'une chose à la fois. Comment attendre un résultat lent sans figer toute la page ? C'est tout l'enjeu de l'asynchrone.
# Le problème : ne pas bloquer
JavaScript s'exécute sur un seul fil d'exécution. Si une opération longue s'exécutait de façon bloquante, toute la page serait gelée pendant ce temps : plus aucun clic, plus aucune animation, rien.
La solution : lancer l'opération, continuer le reste du code, et réagir plus tard, quand le résultat est prêt. C'est ça, l'asynchrone : « fais ça, et préviens-moi quand c'est fini ».
# Les callbacks (l'ancienne façon)
Historiquement, on passait une fonction de rappel (callback), exécutée une fois l'opération terminée. L'exemple le plus simple, un délai :
setTimeout(() => {
console.log("2 secondes plus tard");
}, 2000);
console.log("Ceci s'affiche en premier");setTimeout(() => { console.log("2 secondes plus tard");}, 2000); console.log("Ceci s'affiche en premier");Ça marche, mais dès qu'on enchaîne plusieurs opérations dépendantes, le code s'imbrique en pyramide (le fameux callback hell) et devient illisible. D'où l'arrivée des promesses.
# Les promesses (Promise)
Une promesse représente une valeur future : un résultat qui n'est pas encore là, mais qui finira par arriver (ou par échouer). Elle a trois états :
| État | Signification |
|---|---|
| pending | En attente, l'opération est en cours |
| fulfilled | Réussie, la valeur est disponible |
| rejected | Échouée, une erreur est survenue |
On réagit avec .then() (succès) et .catch() (erreur) :
fetch("/api/projets")
.then((reponse) => reponse.json())
.then((data) => console.log(data))
.catch((erreur) => console.error("Échec :", erreur));fetch("/api/projets") .then((reponse) => reponse.json()) .then((data) => console.log(data)) .catch((erreur) => console.error("Échec :", erreur));Chaque .then() renvoie une nouvelle promesse, ce qui permet de chaîner les étapes proprement, sans imbrication.
# async / await (la façon moderne)
async / await est du sucre syntaxique au-dessus des promesses. Il permet d'écrire du code asynchrone qui se lit comme du code synchrone, de haut en bas.
Sucre syntaxique : une écriture plus agréable pour faire quelque chose qui existe déjà, sans rien ajouter sous le capot. async / await ne remplace pas les promesses - il les habille pour les rendre plus lisibles.
async function chargerProjets() {
try {
const reponse = await fetch("/api/projets");
const data = await reponse.json();
console.log(data);
} catch (erreur) {
console.error("Échec :", erreur);
}
}async function chargerProjets() { try { const reponse = await fetch("/api/projets"); const data = await reponse.json(); console.log(data); } catch (erreur) { console.error("Échec :", erreur); }}Deux règles :
- Le mot-clé
awaits'utilise à l'intérieur d'une fonctionasync. awaitmet en pause la fonction jusqu'à ce que la promesse soit résolue, sans bloquer le reste de la page.- La gestion d'erreur passe par un bloc
try/catch, comme pour du code classique.
C'est la forme qu'on privilégie aujourd'hui : plus lisible que les chaînes de .then().
# fetch : appeler une API
fetch est la fonction intégrée pour faire des requêtes réseau. Elle renvoie une promesse, donc elle se marie parfaitement avec async / await.
API (Application Programming Interface) : un point d'entrée qui permet à un programme d'en interroger un autre. Ici une API web : on envoie une requête à une URL, le serveur renvoie des données (souvent en JSON).
async function getUtilisateur(id) {
const reponse = await fetch(`https://api.exemple.fr/users/${id}`);
if (!reponse.ok) {
throw new Error(`Erreur HTTP : ${reponse.status}`);
}
return reponse.json();
}async function getUtilisateur(id) { const reponse = await fetch(`https://api.exemple.fr/users/${id}`); if (!reponse.ok) { throw new Error(`Erreur HTTP : ${reponse.status}`); } return reponse.json();} fetch ne rejette la promesse qu'en cas d'erreur réseau. Un code 404 ou 500 est considéré comme une réponse « reçue » : c'est à toi de vérifier reponse.ok et de gérer le cas. Ce portfolio fait exactement ça pour interroger l'API GitHub.
# À retenir
- JavaScript est monothread : l'asynchrone évite de bloquer la page pendant une opération longue.
- Une promesse représente une valeur future (
.then()/.catch()). async/awaitrend le code asynchrone lisible, avec la gestion d'erreur entry/catch.fetchsert à appeler une API. Pense à vérifierreponse.ok.
Ces réflexes se retrouvent directement en React et Next.js, où récupérer des données (dans un Server Component async, par exemple) repose sur exactement les mêmes outils.