Ce qui suit est une traduction d'un article du blog de David Catuhe (Microsoft) que je remercie pour avoir donné aimablement son accord
JavaScript en a fait du chemin depuis ses premières versions, et grâce à tous les efforts réalisés par le TC39 (L'organisation en charge de la standardisation de JavaScript, ou ECMAScript pour être exact), nous avons maintenant un langage moderne qui est largement utilisé.
Une des parties d'ECMAScript qui a reçu de grandes améliorations est la programmation asynchrone. Vous pouvez en apprendre plus sur la programmation asynchrone ici si vous êtes un nouveau développeur. Heureusement, nous avons inclus ces changements dans le nouveau navigateur Edge de Windows 10. Consultez le journal des modifications ci-dessous :
https://dev.modern.ie/platform/changelog/desktop/10547/
Parmi toutes ces nouvelles fonctionnalités, nous allons nous concentrer en particulier sur les "Fonctions async ES2016" (ES2016 Async Functions), effectuer un voyage à travers ces mises à jour et voir comment ECMAScript peut améliorer votre travail au quotidien dès aujourd'hui.
Première étape : ECMAScript 5 - Callback City
ECMAScript 5 (et les versions antérieures) ne jurent que par les callbacks (fonctions auxiliaires). Pour illustrer ceci, prenons un exemple simple que vous utilisez certainement plus d'une fois par jour : l'exécution d'une requête XHR.
Code javascript : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | var displayDiv = document.getElementById("displayDiv"); // Part 1 - Defining what do we want to do with the result var processJSON = function (json) { var result = JSON.parse(json); result.collection.forEach(function(card) { var div = document.createElement("div"); div.innerHTML = card.name + " cost is " + card.price; displayDiv.appendChild(div); }); } // Part 2 - Providing a function to display errors var displayError = function(error) { displayDiv.innerHTML = error; } // Part 3 - Creating and setting up the XHR object var xhr = new XMLHttpRequest(); xhr.open('GET', "cards.json"); // Part 4 - Defining callbacks that XHR object will call for us xhr.onload = function(){ if (xhr.status === 200) { processJSON(xhr.response); } } xhr.onerror = function() { displayError("Unable to load RSS"); } // Part 5 - Starting the process xhr.send(); |
Les développeurs JavaScript chevronnés noteront à quel point cela leur semble familier puisque les callbacks pour XHR sont utilisées tout le temps ! C'est simple et relativement direct : le développeur crée une requête XHR, puis fournit le callback de l'objet XHR spécifié.
En revanche, la complexité du callback vient de l'ordre d'exécution qui est non linéaire en raison de la nature intrinsèque de la programmation asynchrone :
"L'Enfer des callbacks" peut même être pire lorsque vous utilisez un autre appel asynchrone au sein de votre propre callback.
Seconde étape : ECMAScript 6 – Promises City
ECMAScript 6 est sur une bonne dynamique d'adoption où Edge détient le meilleur score avec 88% (en mode expérimental).
Parmi de nombreuses améliorations d'importances, ECMAScript 6 standardise l'utilisation des promises (anciennement connues sous le nom de futures).
Selon MDN, une promise est un objet qui est utilisé pour les opérations déportées (deferred) et asynchrones. Une promise représente une opération qui ne s'est pas encore terminée, mais qui est prévue de l'être à l'avenir. Les promises sont une façon d'organiser les opérations asynchrones de façon à ce qu'elles apparaissent synchrones dans le code. Exactement ce dont nous avons besoin pour notre exemple avec XHR.
Les promises existent depuis un certain temps, mais la bonne nouvelle est que maintenant vous n'avez plus à utiliser une bibliothèque JavaScript puisqu'elles sont fournies dans le navigateur.
Mettons légèrement à jour notre exemple précédent pour utiliser les promises et voyons comment cela améliore la lisibilité et la maintenabilité de notre code :
Code javascript : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | var displayDiv = document.getElementById("displayDiv"); // Part 1 - Create a function that returns a promise function getJsonAsync(url) { // Promises require two functions: one for success, one for failure return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.onload = () => { if (xhr.status === 200) { // We can resolve the promise resolve(xhr.response); } else { // It's a failure, so let's reject the promise reject("Unable to load RSS"); } } xhr.onerror = () => { // It's a failure, so let's reject the promise reject("Unable to load RSS"); }; xhr.send(); }); } // Part 2 - The function returns a promise // so we can chain with a .then and a .catch getJsonAsync("cards.json").then(json => { var result = JSON.parse(json); result.collection.forEach(card => { var div = document.createElement("div"); div.innerHTML = `${card.name} cost is ${card.price}`; displayDiv.appendChild(div); }); }).catch(error => { displayDiv.innerHTML = error; }); |
Ci-dessus, vous avez peut-être remarqué beaucoup d'améliorations. Regardons de façon plus attentive.
Création de la promise
Afin de "promisifier" (désolé pour le néologisme) l'ancien objet XHR, vous devez créer un objet Promise :
Utilisation de la promise
Une fois créée, la promise peut être utilisée pour enchaîner les appels asynchrones de manière plus élégante :
Nous avons donc maintenant (du point de vue de l'utilisateur) :
- Récupéré la promise (1)
- Enchaîné avec le code de succès (2 et 3)
- Enchaîné avec le code d'erreur (4) comme dans un bloc try/catch
Ce qui est intéressant est que les promises chaînées sont facilement appelables à l'aide de .then().then(), etc.
Remarque : Puisque JavaScript est un langage moderne, vous remarquerez peut-être que j'utilise aussi le sucre syntaxique d'ECMAScript 6 comme l'interpolation de chaînes ou la notation fléchée (arrow function).
Terminus : ECMAScript 7 – Asynchronous city
Enfin, nous avons atteint notre destination ! Nous sommes presque dans le futur, mais grâce au cycle de développement rapide d'Edge, l'équipe est en mesure d'introduire un peu d'ECMAScript 7 avec des fonctions async dans la dernière version !
Les functions async sont un sucre syntaxique pour améliorer le modèle au niveau du langage dans le but d'écrire du code asynchrone.
Les fonctions async sont construites par dessus les fonctionnalités d'ECMAScript 6 comme les générateurs. En effet, les générateurs peuvent être utilisées conjointement avec des promises pour produire les mêmes résultats, mais avec beaucoup plus de code d'utilisateur.
On n'a pas besoin de changer la fonction qui génère la promise dans la mesure où les fonctions async travaillent directement avec la promise.
Nous avons seulement besoin de changer la fonction d'appel :
Code javascript : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // Let's create an async anonymous function (async function() { try { // Just have to await the promise! var json = await getJsonAsync("cards.json"); var result = JSON.parse(json); result.collection.forEach(card => { var div = document.createElement("div"); div.innerHTML = `${card.name} cost is ${card.price}`; displayDiv.appendChild(div); }); } catch (e) { displayDiv.innerHTML = e; } })(); |
C'est ici que la magie intervient. Ce code ressemble à du code synchrone normal avec une exécution parfaitement linéaire :
Plutôt impressionnant, n'est-ce pas ?
Et la bonne nouvelle est que vous pouvez même utiliser les fonctions async avec la notation fléchée ou les méthodes de classe.
Pour aller plus loin
Si vous voulez plus de détails sur la façon dont nous avons implémenté Chakra, vous pouvez vous rendre sur le message officiel du blog de Edge :
http://blogs.windows.com/msedgedev/2...icrosoft-edge/
Vous pouvez également suivre la progression de l'implémentation d'ECMAScript 6 et 7 dans les différents navigateurs en utilisant le site Web de Kangax : N'hésitez pas également à jeter un oeil sur notre feuille de route JavaScript !
S'il vous plaît, n'hésitez pas à nous donner un retour et à soutenir vos fonctions préférées en utilisant le bouton de vote :
Merci d'avoir lu et nous sommes impatients d'entendre vos commentaires et vos idées !
David Catuhe
Principal Program Manager
@deltakosh