18 Nov 2016

Les tips Javascript – ES7 et les mots clés async/await

Depuis Janvier dernier, une fonctionnalité intéressante est passée en stage 3 (l’équivalent du Release Candidate dans le monde de la programmation) dans les spécifications ES2016. Si tout se passe bien elle devrait être validée à la fin de ce mois-ci. Il s’agit de l’utilisation des mots-clés async et await.

Ces dernières années nous avons vu fleurir l’utilisation des promises afin de faire de la programmation asynchrone. Si vous ne voyez pas de quoi je parle je vous conseille de faire un tour sur le MDN pour bien comprendre de quoi il en retourne. En effet ces 2 mots clés permettent de simplifier l’utilisation des promises.

Si vous programmez en C# cette notation devrait vous être familière puisqu’elle existe depuis 2012, avec la sortie du framework .Net 4.5. Elle permet de rajouter un peu de sucre syntaxique dans notre code afin de simplifier la partie technique permettant de gérer des tâches asynchrones, afin de se concentrer le plus possible sur notre code métier.

En Javascript c’est exactement pareil. async permet de marquer une méthode comme asynchrone, et await de faire un appel asynchrone à l’intérieur de cette méthode, attendre la fin de l’appel et retourner son résultat. La méthode marquée va alors pouvoir retourner un objet qui sera renvoyé de manière asynchrone au travers l’utilisation d’une promise (à la manière d’un Promise.resolve(monObjet) ).

Les 2 mots clés sont indissociables, utiliser l’un sans l’autre générera des erreurs.

 

J’ai rien compris, je peux avoir un exemple?

Nous utilisons pas mal Angular 1 au Webcenter. Dans mon application j’aimerai récupérer un utilisateur. Aujourd’hui à l’aide des promises nous le ferions de cette manière.

La syntaxe est plutôt courte (il est loin le bon vieux temps ou l’on enchaînait les callbacks!), mais il y a moyen de simplifier encore plus cette notation à l’aide de nos 2 mots clés.

La syntaxe est tout de suite plus légère et lisible. Comme vous pouvez le voir, la methode get() de notre service attend un objet en retour, mais c’est bien une promise qui est retourné lors de l’appel à usersService.get(userId) dans notre controlleur. L’utilisation du await dans ce dernier permet alors d’attendre la résolution de notre promise et de setter son résultat dans la variable this.user.

Et comme une fonction marquée comme async retourne une promise, il est tout à fait possible de l’utiliser dans notre service mais d’utiliser l’ancienne syntaxe dans notre controlleur.

Attention, par défaut Angular 1 utilise $q pour gérer les promises, qui n’est pas compatible avec cette syntaxe. si vous utilisez $http il vous faudra donc une couche intermédiaire entre votre service et ce dernier.

 

Okay, mais comment je gère les erreurs du coup?

Tout simplement en utilisant des try/catch! c’est un peu plus verbeux, mais rend le code plus standard et compréhensif. Soyons honnêtes, vous avez tout de suite compris que le second argument de votre promise était la méthode appelée en cas d’échec?

Voici ce que ça donnera dans notre controleur:

l’argument du catch correspondra alors à la raison passé en paramètre lors du rejet de notre promise (Dans un Promise.reject(maRaison) par exemple).

 

On peut aussi chaîner les appels asynchrones?

Biensûr! il suffit de chaîner les await vu que l’exécution du code s’arrête tant que la promise n’est pas résolue.

 

Et si je veux attendre plusieurs appels asynchrones en même temps?

Et bien malheureusement ce n’est pas possible directement avec cette syntaxe. Un mot clé avait été proposé, mais la proposition a depuis été supprimée des drafts. Elle reviendra peut-être dans ES8! En attendant vous devrez continuer à utiliser Promise.all avec votre tableau de promises. Vous pouvez néanmoins utiliser le mot clé await devant Promise.all pour récupérer un tableau des retours des différentes promises.

ou encore plus simple avec la syntaxe ES6

 

Cool, il y a d’autres trucs que je dois savoir?

Quelques-uns, par exemple que c’est supporté nativement par… aucun navigateur. Par contre c’est supporté par Babel et Typescript depuis quasiment un an. Donc si vous faites déjà de l’ES6 il y a de grandes chances pour que vous puissiez l’utiliser.

Et pour rappel, le mot clé await attend (d’ou son nom ;)) que votre appel asynchrone soit terminé et donc bloque la suite de votre code. Utilisez le donc en connaissance de cause!

 

Bons appels asynchrones!

Share