LES PROMESSES EN JAVASCRIPT

ECMAScript 2015, ES6 pour les intimes, est le dernier standard d'implémentation du langage javascript. Au menu, un paquet de nouvelles fonctionnalités qui veulent assurer au langage une pole position dans la course aux technos web.

Pourquoi l'utiliser ?

Le principal apport de l'ES6 n'est pas, en soi, une amélioration des performances du langage. Ce travail est laissé aux interpréteurs de javascript tels que V8 et SpikerMonkey.

Ce que l'ES6 apporte, c'est une platée de nouvelles syntaxes pour rendre le code javascript plus élégant, plus maintenable, plus "flat" (avec les promesses) et mieux "scopé" (grâce aux nouveaux mots clés let & const).

 

Les promesses

L'objet Promise (pour « promesse ») est utilisé pour réaliser des traitements de façon asynchrone. Une promesse représente une unique opération asynchrone qui n'a pas encore été complétée, mais qui est attendue dans le futur (MDN).

Plus concrètement, les promesses sont des objets apportant une nouvelle syntaxe au javascript qui permet de mettre à plat ce qu'on appelle techniquement le "code spaghetti ".

// callback-based functions
function spaghettiCode() {
  asyncStuff(function (err, res) {
    if (err) { throw err; }
    moreAsyncStuff(function (err, res) {
      if (err) { throw err; }
      andMoreAsyncStuff(function (err, res) {
        if (err) { throw err; }
        oneLastAsyncStuff(function (err, res) {
          if (err) { throw err; }
        });
      });
    });
  });
}

// promise-based functions
function flatCode() {
  asyncStuff()
  .then(moreAsyncStuff)
  .then(andMoreAsyncStuff)
  .then(oneLastAsyncStuff)
  .catch(function (err) {
    throw err;
  });
}

Voilà deux exemples plus détaillés où l'on utilise la fonction setTimout wrappée dans une promesse :

function setTimeoutPromise (duration) {
  return new Promise(function (resolve) {
    setTimeout(resolve, duration);
  });
}
function logArguments () {
  console.log(arguments);
}

// use case 1
setTimeoutPromise(1000)
.then(logArguments);

// display after 1s:
// ['done']

//use case 2
setTimeoutPromise(1000)
.then(logArguments.bind({}, 'tic'))
.then(setTimeoutPromise.bind({}, 2000)
.then(logArguments.bind({}, 'tac'))
.then(function () {
  throw 'oups';
})
.then(logArguments.bind({}, 'code should\'n\'t be reached'))
.catch(logArguments);

// display after 1s:
// ['tic']
// display after 2 more seconds:
// ['tac']
// ['oups']

Comment l'utiliser ?

Au sein de la team Player de France Télévisions, en charge du développement de leur lecteur de vidéo web, deux facteurs bloquaient son utilisation.

Server-side :

Le facteur bloquant dans nos projets Node.JS était notre solution de code-coverage qui ne supportait pas l'ES6. En effet, nous utilisions une solution maison (covy https://github.com/samjoch/covy ) basée sur l'outil de coverage blanket (https://github.com/alex-seville/blanket) qui n'est plus maintenu. La solution, assez simple à mettre en œuvre, a été de remplacer cet outil par son fils spirituel : istanbul (https://github.com/gotwarlost/istanbul).

Mais le principal facteur bloquant sur un projet pourrait être la version de Node.JS déployée sur votre infrastructure. L'implémentation de l'ES6 est complète à 59% pour la v5 et à 99% pour Node.JS v6. Cette couverture est dépendante de celle de V8, moteur de javascript utilisé par Node.JS.

Quelques petits détails sur les versions de Node.JS pour vous encourager à mettre à jour votre infrastructure :

* v0.10 v0.12 : La période du support arrive à son terme, il devient dangereux de rester sur cette version.

* v4 : La v6 passe en Long-Term Support le 01/10, il est temps de se mettre à jour !

* v5 : Cette version n'est plus maintenue et a été remplacée par la v6 dans la roadmap de Node.JS, il est temps de se mettre à jour !

* v6 : Vous êtes à jour !

* v7 : Soon.

Client-side

De ce côté-là, c'est un peu plus compliqué. Pas d'ES6 sans un navigateur à jour, et encore : https://kangax.github.io/compat-table/es6/

Heureusement, il existe des solutions. Celle adoptée par la team Player est d'utiliser le builder webpack couplé à Babel. Babel est un transpiler, il va transformer votre code ES6 en bon vieux code Javascript de derrière les fagots, compatible avec tous les navigateurs. L'intérêt : votre code est plus élégant, plus lisible, prêt pour le futur et tout cela sans perdre en compatibilité.

Subsiste la question suivante : l'utilisation d'un transpiler ne risque-t-elle pas de diminuer les performances de l'application ? Globalement, il est possible de rencontrer une légère baisse des performances. Si c'est un facteur primordial pour vous car le matériel que vous ciblez dispose de performances très faibles (je pense notamment aux smartTVs et aux box FAI) et que vous n'utilisez que du Javascript vanilla, alors je ne vous recommanderais pas d'utiliser de l'ES6 transpilé. Sinon, la diminution des performances est négligeable.

Plus de détails ici : https://kpdecker.github.io/six-speed/

 

En conclusion

L'ES6 apporte un vent de fraîcheur sur le Javascript. Avec Node.JS, il est facile à intégrer, il n'y a pas de raison de se priver ! Client-side, la démarche demandera plus de travail mais s'avérera payante sur le long terme. Il y a beaucoup choses à savoir sur les promesses, avec notamment quelques subtilités dont il est facile de passer à côté.

J'ai écrit un article que j'espère relativement complet à propos de ce sujet : 
https://waidd.github.io/2016/09/28/ECMAScript2015-promises.html

Mais les promesses restent relativement simples à prendre en main et apportent, lorsqu'elles sont bien utilisées, un vrai plus en lisibilité dans votre projet. Il y a beaucoup de choses à dire sur les autres fonctionnalités de l'ES6, donc, à suivre !

 

Thomas C

 

Ajouter un commentaire