Cours Node.js Cours Node.js - Partie 2 - Programmation asynchrone et requête à d'autres APIs

Dans la partie précédente, nous avons appris:

Jusqu’à présent, nous n’avons appelé et défini que des fonctions synchrones. C’est à dire que Node.js exécute ces fonctions de manière séquentielle.

L’appel à une fonction synchrone bloque l’exécution du programme jusqu’à la fin du traitement qu’elle effectue. Lorsqu’un traitement a une durée indéterminée, il est inacceptable qu’un serveur attende la fin de ce traitement, car cela l’empêcherait de répondre à d’autres requêtes pendant ce temps là. C’est pour éviter cela que nous allons apprendre à utiliser des fonctions asynchrones.

Objectifs de cette partie

Prérequis:

Durée estimée: 4 heures.


Exercice 1 - Envoi de requête à l’aide d’un callback

Dans la partie précédente, nous avons développé un serveur d’API HTTP: un programme qui répond à des requêtes.

Dans cet exercice, nous allons écrire un programme qui émet une requête HTTP GET vers l’API d’un autre serveur. Nous allons donc développer un client d’API, afin de découvrir le concept d’appel de fonction asynchrone avec callback. (cf aide-mémoire: Fonctions synchrones VS asynchrones)

👉 Exerciseur en ligne: Envoi de requête à l’aide d’un callback

🤖 Execution du robot de correction en local:

$ npm install github:adrienjoly/cours-nodejs # une fois pour toutes, pour installer le robot
$ npx cours-nodejs test 2-1 get.js # pour faire tester get.js au robot de l'exercice 1 de la partie 2

Indice: exemple d’usage de request.

Note: En dehors de ce cours, n’utilisez pas le module request, car il est déprécié.


Exercice 2 - Gestion d’erreurs de callback

Dans l’exercice précédent, nous sommes naïvement partis du principe que la requête fonctionnerait systématiquement. Cela revient à espérer que l’API interrogée ne sera jamais indisponible et que l’utilisateur de notre programme sera connecté à Internet de manière fiable. En réalité, un programme n’est jamais à l’abri de traitements qui ne se passent pas comme prévu, et c’est au développeur de prévoir et traiter correctement ces cas d’erreur, afin de ne pas laisser l’utilisateur dans l’embarras face à un problème qu’il ne saura pas résoudre.

Dans cet exercice, nous allons volontairement envoyer une requête sur un serveur qui n’existe pas, et afficher l’erreur retournée par l’appel à request() dans la sortie standard.

👉 Exerciseur en ligne: Gestion d’erreurs de callback

🤖 Execution du robot de correction en local:

$ npx cours-nodejs test 2-2 get.js

Indice: exemple d’usage de request.


Exercice 3 - Requête à l’aide de Promise

Dans les exercices 1 et 2, nous avons envoyé une requête HTTP GET à l’aide de la fonction request(). Pour définir le traitement de la réponse (ou erreur) à cette requête, nous avons passé une fonction de callback en paramètre de l’appel à request(). Cette fonction de callbacks sera rappelée (c’est la traduction française de l’expression call back) par la fonction request() une fois que la requête aura réussi ou échoué.

Les fonctions fournies par la bibliothèque standard de Node.js s’appuient généralement sur ce principe de callback pour être informé d’événements asynchrones. Dans l’exercice précédent, l’événement asynchrone qui nous intéressait était la réception d’une réponse à notre requête.

Le concept de promesse (en anglais: Promise; cf javascript.info et Référence MDN) a été intégré au langage JavaScript afin de simplifier le séquençage d’appels asynchrones, et améliorer leur lisibilité en évitant le “callback hell”.

Dans cet exercice, nous allons utiliser une promesse pour récupérer le résultat d’un appel à une fonction asynchrone. Pour cela, nous allons utiliser la bibliothèque node-fetch.

👉 Exerciseur en ligne: Requête à l’aide de Promise

🤖 Execution du robot de correction en local:

$ npx cours-nodejs test 2-3 get.js

Indice: consulter la documentation de node-fetch pour savoir comment l’utiliser. (cf lien fourni ci-dessus)


Exercice 4 - Gestion d’erreurs de Promise

Encore une fois, nous avons implémenté une version naïve de notre requête, en partant du principe que celle-ci se passerait comme prévu.

Dans cet exercice, nous allons volontairement envoyer une requête sur un serveur qui n’existe pas, et afficher dans la sortie standard l’erreur (aussi appelée exception) retournée par la promesse de fetch().

👉 Exerciseur en ligne: Gestion d’erreurs de Promise

🤖 Execution du robot de correction en local:

$ npx cours-nodejs test 2-4 get.js

Indice: consulter les références fournies en fin de page, pour savoir comment récupérer les erreurs lorsqu’on appelle une fonction qui retourne une Promise.


Exercice 5 - Requête à l’aide de await

Le mot clé await a été intégré au langage JavaScript pour simplifier et rendre encore plus lisible l’appel de fonctions asynchrones à base de Promesses.

Dans cet exercice, nous allons utiliser await au lieu de .then() pour afficher la réponse retournée par l’appel à fetch().

👉 Exerciseur en ligne: Requête à l’aide de await

🤖 Execution du robot de correction en local:

$ npx cours-nodejs test 2-5 get.js

Indice: Sachant que await ne peut être employé qu’au sein d’une fonction async, vous allez devoir définir une fonction async et l’appeler dans la foulée pour que la requête soit envoyée. Cf l’exemple fourni dans l’annexe suivante: Fonctions synchrones VS asynchrones.


Exercice 6 - Gestion d’erreurs de await

Encore une fois, nous avons implémenté une version naïve de notre requête, en partant du principe que celle-ci se passerait comme prévu.

Dans cet exercice, nous allons volontairement envoyer une requête sur un serveur qui n’existe pas, intercepter l’erreur renvoyée par await fetch() et afficher cette erreur dans la sortie standard.

👉 Exerciseur en ligne: Gestion d’erreurs de await

🤖 Execution du robot de correction en local:

$ npx cours-nodejs test 2-6 get.js

Indice: Lorsqu’une fonction asynchrone est appelée avec await, les erreurs sont interceptées de la même manière que lorsqu’on appelle une fonction synchrone: à l’aide d’un bloc try-catch. Cf l’exemple fourni dans l’annexe suivante: Fonctions synchrones VS asynchrones.


Exercice 7 - Requête complète

Dans les exercices précédents, nous avons employé les 3 façons d’effectuer un appel de fonction asynchrone: callback, Promise et await. Pour chacune de ces façons de faire, nous avons écrit un programme affichant la réponse quand aucune erreur ne survient, et un exercice séparé ne traitant que les cas d’erreurs.

Nous avons vu que l’usage de await permet d’appeler des fonctions asynchrones et de gérer leurs erreurs comme si ces fonctions étaient synchrones. Ce sucre syntaxique est à privilégier, pour la lisibilité et la robustesse qu’il apporte au code.

Dans cet exercice, nous allons combiner la solution des exercices 5 et 6 afin d’obtenir un programme qui affichera la réponse à la requête ou l’erreur obtenue, selon le cas.

Afin de nous permettre de tester les deux cas à la demande, ce programme:

Par exemple:

node get.js https://jsonplaceholder.typicode.com/photos # affichera la réponse
node get.js https://serveur-inexistant.xyz # affichera un message d'erreur

👉 Exerciseur en ligne: Requête complète

🤖 Execution du robot de correction en local:

$ npx cours-nodejs test 2-7 get.js

Indice: How to parse command line arguments | Node.js.


Exercice 8 - Requête complète, en local

Dans les exercices précédents, votre serveur était exécuté et testé dans le cloud, pour vous aider à focaliser votre attention sur l’écriture du code asynchrone.

Vous allez maintenant re-créer, exécuter et tester le programme de l’exercice 7 sur votre propre ordinateur, en créant un fichier get.js et en ajoutant ses dépendances dans package.json à l’aide de npm.

L’objectif est de pouvoir tester votre programme depuis votre shell Linux, comme montré à la fin de l’énoncé précédent.


Exercice 9 - Requête complète, sur Heroku

Maintenant que votre programme fonctionne localement, déployez le en production, sur Heroku.

Comment pouvons-nous tester que la requête fonctionne ?

À l’aide d’Express, ajoutez une route qui effectuera la requête à la demande et retournera le résultat (réponse ou message d’erreur) en réponse de toute requête adressée à cette route.


Prise de recul: appels synchrones et asynchrones

Questions auxquelles savoir répondre:


Pour aller plus loin

Ressources sur l’exécution de code asynchrone

Manières d’effectuer une requête HTTP depuis Node.js

Il existe plusieurs manières d’effectuer des requêtes HTTP depuis Node.js.

Notamment:

Quelle solution préférez-vous ? Pourquoi ?