11-1 Introduction à la programmation asynchrone
Dans les étapes suivantes, nous utiliserons des principes de la programmation asynchrone:
- Les
Promise
- Les instructions
async/await
Afin de mettre en lumière ces différents concepts, voici une brève introduction à ces concepts.
Vous n'avez pas nécessairement à reproduire ces exemples de votre côté, mais plutôt de lire et comprendre les principes généraux présentés. Vous aurez l'occasion de les implémeter par vous-même bientôt.
Les Promise
Assumons un appel d'API utilisant la fonction native fetch
permettant de faire des requêtes HTTP
.
function main(){
const response = fetch('https://http.cat/413');
console.log(response);
console.log('Terminé!');
}
main();
Si on exécute cela, on s'attendrait à voir dans la console la réponse, puis ensuite le texte Terminé
. Pourtant, on observe plutôt ceci:
Promise { <pending> }
Terminé!
Si on regarde la signature de la fonction fetch
, on remarque qu'elle retourne un objet Promise
.
Une promesse est un objet (Promise
) qui représente la complétion ou l'échec d'une opération asynchrone
L'opération est donc exécutée en arrière-plan et on doit attendre le résultat de l'opération avant de l'afficher. Une requête d'API est un excellent exemple de requête asynchrone puisque la requête peut prendre plus ou moins de temps tout dépendant de l'opération et de l'état du réseau.
Attendre le résultat d'une Promise
avec then
On peut attendre le résultat d'une Promise
en utilisant then
, suivi d'une fonction anonyme à exécuter à la suite de la complétion de l'opération.
function main() {
fetch('https://http.cat/413').then((reponse) => {
console.log(reponse.status);
});
console.log("Terminé!");
}
main();
Preuve que l'opération est asynchrone, voici le résultat dans la console:
Terminé!
200
Terminé!
est affiché avant le résultat de la requête! Cela est normal puisque l'opération HTTP est exécutée de façon asynchrone, donc on passe tout de suite à l'instruction suivante. Seulement lorsque l'opération est complétée que la fonction anonyme contenant console.log(reponse.status);
est exécutée.
Attraper les erreurs avec catch
Il est possible d'attraper les erreurs en chainant une fonction anonyme de plus via l'instruction catch
.
function main() {
fetch('https://http.cat/413').then((reponse) => {
console.log(reponse.status);
}).catch((error) => {
console.log(error);
});
console.log("Terminé!");
}
main();
Dans le cas où une erreur subviendrait, c'est le bloc (fonction anonyme) catch
qui serait exécuté.
Async / await
Le code précédent fonctionne, mais vous voyez rapidement les lacunes:
- Beaucoup de fonctions anonymes (communément appelé
callback hell
) - Le code peut être difficile à suivre
De plus, que faire si on veut réellement faire afficher Terminé
après le retour? On doit évidemment le mettre dans la fonction anonyme. Et si on avait plusieurs fonctions asynchrones? C'est là que le tout devient très difficile à gérer avec les then
qui s'enchainent.
Pour améliorer la lisibilité et l'exécution du code, on peut utiliser les instructions async
et await
.
await
Permets à un appel asynchrone de se comporter comme un appel synchrone en attendant le retour avant de passer à la prochaine instruction.
On peut remplacer tout le code précédent par ceci:
async function main() {
const reponse = await fetch('https://http.cat/413');
console.log(reponse.status);
console.log('Terminé!');
}
main();
L'instruction await
ne peut être utilisée que dans une fonction asynchrone et donc avec l'instruction async
devant la déclaration de la fonction.
La fonction se comporte maintenant de façon synchrone et cela est beaucoup plus facile à gérer! En effet, voici la sortie dans la console:
200
Terminé!
Try / Catch
La gestion des erreurs est aussi beaucoup plus intuitive puisqu'il devient possible d'utiliser un simple Try / Catch
pour gérer les erreurs.
async function main() {
try {
const reponse = await fetch('https://http.cat/413');
console.log(reponse.status);
} catch (error) {
console.log(error);
}
console.log('Terminé!');
}
main();
Non-bloquant pour le thread
principal
Les opérations async
et await
, bien que donnant l'impression d'exécuter du code de façon synchrone, n'est pas bloquant pour le thread
principal de l'application et n'empêche pas d'autres instructions en parallèle d'être exécutées.