• 12 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 22/07/2020

Gérez du code asynchrone

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Nous allons maintenant voir comment on peut exécuter du code asynchrone et renvoyer le résultat que l'on souhaite à celui qui a lancé le code.

Callbacks

C'est la méthode la plus "vieille" mais toujours utilisée par beaucoup de modules JavaScript (nous verrons ce que sont les modules dans la dernière partie de ce cours). Une callback est simplement une fonction que vous définissez. Le principe de la callback  est de la passer en paramètre d'une fonction asynchrone. Une fois que la fonction asynchrone a fini sa tâche, elle va appeler notre fonction callback en lui passant un résultat. Ainsi, le code que nous mettons dans notre fonction callback sera exécuté de manière asynchrone. Cela ne vous rappelle pas quelque chose ? Les événements ! Les événements sont un exemple typique de fonction asynchrone à laquelle on passe une fonction callback.

element.addEventListener('click', function(e) {
// Do something here ...
});

Dans l'exemple ci-dessus, la fonction qui est envoyée à  addEventListener  est une callback. Elle n'est pas appelée tout de suite, elle est appelée plus tard, dès que l'utilisateur clique sur l'élément. Ça ne bloque donc pas l'exécution du code et c'est donc asynchrone 😁.

Les callbacks sont la base de l'asynchrone en JavaScript et sont très utilisées.

Par exemple, lorsque nous définissions une fonction dans la propriété  onreadystatechange, nous étions en train de lui définir une callback. De la même manière, la fonction que nous passons en paramètre à  setTimeout  est une callback.

Les callbacks sont faciles à comprendre et à utiliser, mais elles souffrent d'un gros problème de lisibilité du code, via ce qu'on appelle le callback hell. En effet, on se retrouve régulièrement dans des situations où on va imbriquer plusieurs couches de callbacks , rendant le code difficile à lire et pouvant générer des erreurs.

elt.addEventListener('click', function(e) {
mysql.connect(function(err) {
mysql.query(sql, function(err, result) {
fs.readFile(filePath, function(err, data) {
mysql.query(sql, function(err, result) {
// etc ...
});
});
});
});
});

 Ce code, qui n'est pas facile à lire, pourrait pourtant correspondre à un cas d'utilisation concret des callbacks : dès que l'utilisateur clique sur un élément, on ouvre une connexion MySQL, puis on récupère des données depuis la base de données, on lit un contenu dans un fichier et on fait une nouvelle requête MySQL, etc.

C'est bien beau de gérer du code asynchrone, mais rien ne vous garantit que tout se soit bien passé. Il nous faut donc un mécanisme pour savoir si une erreur est survenue !

Gestion des erreurs

Pour gérer les erreurs avec les callbacks, la méthode la plus utilisée est de prendre 2 paramètres dans notre callback. Le 2e paramètre est notre donnée et le 1er est l'erreur. Si elle n'est pas null ou undefined,  elle contiendra un message d'erreur indiquant qu'une erreur est intervenue.

Si on reprend l'exemple ci-dessus, on voit par exemple que la lecture d'un fichier avec le module  fs  peut nous retourner une erreur :

fs.readFile(filePath, function(err, data) {
if (err) {
throw err;
}
// Do something with data
});

Promises

Les promises, ou promesses en français, sont un peu plus complexes mais bien plus puissantes et faciles à lire que les callbacks.

Lorsque l'on exécute du code asynchrone, celui-ci va immédiatement nous retourner une "promesse" qu'un résultat nous sera envoyé prochainement.

Cette promesse est en fait un objet Promise qui peut être  resolve  avec un résultat, ou  reject  avec une erreur.

Lorsque l'on récupère une  Promise , on peut utiliser sa fonction  then()  pour exécuter du code dès que la promesse est résolue, et sa fonction  catch()  pour exécuter du code dès qu'une erreur est survenue.

Voyons avec un exemple concret pour mieux comprendre :

functionThatReturnsAPromise()
.then(function(data) {
// Do somthing with data
})
.catch(function(err) {
// Do something with error
});

Dans l'exemple ci-dessus, la fonction  functionThatReturnsAPromise  nous renvoie une  Promise . On peut donc utiliser sa fonction  then()  en lui passant une fonction qui sera exécutée dès qu'un résultat sera reçu (avec le résultat en question passé à notre fonction). On peut aussi utiliser sa fonction  catch()  en lui passant une fonction qui sera exécutée si une erreur est survenue (avec l'erreur en question passée à notre fonction).

Le gros avantage est que l'on peut aussi chaîner les  Promises. Ainsi, la valeur que l'on retourne dans la fonction que l'on passe à   then()  est transformée en une nouvelle  Promise  résolue, que l'on peut utiliser avec une nouvelle fonction  then() . Si notre fonction retourne par contre une exception, alors une nouvelle  Promise  rejetée est créée et on peut l'intercepter avec la fonction  catch() . Mais si la fonction que l'on a passée à  catch()  retourne une nouvelle valeur, alors on a à nouveau une  Promise  résolue que l'on peut utiliser avec une fonction  then() , etc.

Voici un exemple qui vous montre comment on peut profiter des  Promise  pour chaîner notre code asynchrone :

returnAPromiseWithNumber2()
.then(function(data) { // Data is 2
return data + 1;
})
.then(function(data) { // Data is 3
throw new Error('error');
})
.then(function(data) {
// Not executed
})
.catch(function(err) {
return 5;
})
.then(function(data) { // Data is 5
// Do something
});

Dans l'exemple ci-dessus, la fonction  returnAPromiseWithNumber2  nous renvoie une  Promisequi va être résolue avec le nombre  2. La première fonction  then()  va récupérer cette valeur. Puis, dans cette fonction on retourne  2 + 1 , ce qui crée une nouvelle  Promise  qui est immédiatement résolue avec  3 . Puis, dans le  then()  suivant, nous retournons une erreur. De ce fait, le  then()  qui suit ne sera pas appelé et c'est le  catch()  suivant qui va être appelé avec l'erreur en question. Lui-même retourne une nouvelle valeur qui est transformée en Promise  qui est immédiatement résolue avec la valeur  5. Le dernier  then()  va être exécuté avec cette valeur.

Gestion des erreurs

Nous avons déjà vu comment se gèrent les erreurs avec les  Promises . Une erreur correspond à une exception qui a été lancée, et il est possible de l'intercepter en appelant la fonction  catch()  de la  Promise .

Async/await

async  et  await  sont 2 nouveaux mots clés qui permettent de gérer le code asynchrone de manière beaucoup plus intuitive, en bloquant l'exécution d'un code asynchrone jusqu'à ce qu'il retourne un résultat.

async function fonctionAsynchrone1() {/* code asynchrone */}
async function fonctionAsynchrone2() {/* code asynchrone */}
async function fonctionAsynchrone3() {
const value1 = await fonctionAsynchrone1();
const value2 = await fonctionAsynchrone2();
return value1 + value2;
}

Dans cet exemple, nous avons un total de 3 fonction asynchrones :  fonctionAsynchrone1 ,  fonctionAsynchrone2 ,  fonctionAsynchrone3 . Quand on utilise  async  et  await , une fonction asynchrone doit avoir le mot clé  async  avant la fonction. Ensuite, dans le code, nous pouvons faire appel à des fonctions asynchrones et attendre leur résultat grâce au mot clé  await  que l'on met devant l'appel de la fonction.

Gestion des erreurs

async / await utilisant les Promises, la levée d'une erreur se fait aussi par une exception.

Pour intercepter cette erreur, par contre, il suffit d'exécuter notre code asynchrone dans un bloc  try {} catch (e) {} , l'erreur étant envoyée dans le catch.

Pratiquez !

Rendez-vous sur cet éditeur CodePen pour réaliser l'exercice suivant.

Dans cet exercice j'ai créé 2 fonctions asynchrones (avec le mot clé asyncgetNumber1() et getNumber2()

  1. Dans un premier temps nous allons créer une fonction asynchrone (avec async) qui s'appelle compute et qui va récupérer les résultats des 2 fonctions asynchrones getNumber1() et getNumber2() (avec await) et renvoyer la somme des 2 valeurs récupérées.

  2. Maintenant nous allons appeler notre fonction compute() et utiliser sa valeur de retour comme une Promise pour finalement afficher le résultat de la promesse dans le contenu HTML de l'élément ayant pour ID result

En résumé

Dans ce chapitre, vous avez appris :

  • Ce qu'est une callback ;

  • Ce que sont les  Promises

  • Comment utiliser  async  et  await

Nous connaissons maintenant 3 techniques pour faire du code asynchrone et pouvoir utiliser sa valeur ; voyons maintenant comment ça peut nous servir dans le cas de plusieurs requêtes HTTP !

Exemple de certificat de réussite
Exemple de certificat de réussite