Lorsque j'ai découvert les Promises (aussi appelées "promesses" en français) il y a quelques années, je dois avouer que j'ai eu du mal à les appréhender tout de suite.

Étant donné que je travaillais depuis longtemps avec des callbacks pour mes opérations asynchrones, je ne voyais pas bien la différence entre les deux systèmes, parce que dans le fond, le fonctionnement était plus ou moins le même !

On passe une ou plusieurs fonctions retour à une fonction asynchrone, et cette dernière l'exécute à la fin de l'opération asynchrone, c'est la même chose.

Alors qu'en fait, la réponse se situe entre les deux.

Une promise est un ensemble de callbacks "normalisé" !

Le principe

Prenons pour exemple une méthode asynchrone fictive, basée sur la fonction Javascript setTimeout(callback, ms) que l'on souhaite utiliser pour créer un délai dans notre code.

La version callback de notre méthode ressemblerait à ça :

//On créé notre méthode qui prend deux callbacks en paramètres
function timer(delay, on_success, on_error){
  if(delay < 10000){
      setTimeout(on_success, delay);
  } else {
      on_error("Timer too long");
  }
}

//Puis on teste cette méthode
console.log("Started...")
timer(3000, function(){
    console.log("Finished!");
}, function(e){
    console.error(e);
});

//Le log "Finished!" apparait 3 secondes après, tout fonctionne

Cette méthode est correcte, elle fonctionne parfaitement, mais si l'implémentation est lisible , l'utilisation elle, ne coule pas vraiment de source.

Comment savoir d'un coup d'oeil lequel du premier ou du deuxième callback est celui qui est exécuté si il y a une erreur, à part en lisant attentivement le code, ou en remontant à l'implémentation de la méthode d'origine ?

De plus, si l'on veut enchainer les timers, il va falloir empiler le code et donc les callbacks, ce qui devient très vite illisible et risque d'engendrer des erreurs malencontreuses.

Et si il était possible de créer un ensemble de callbacks normalisé, intuitif à l'utilisation et géré nativement par le langage ? Bienvenue dans le monde merveilleux des Promises !

//On créé la même méthode, mais pas besoin de passer des callbacks, tout va se jouer dans le retour de la fonction
function timerPromise(delay){
  return new Promise(function(resolve, reject){
    if(delay < 10000){
      setTimeout(resolve, delay);
    } else {
      reject("Timer too long");
    }
  });
}

//Ici, on va même pouvoir enchaîner les appels, sans perdre en lisibilité
console.log("Started...")
timerPromise(1000).then(function(){
	return timerPromise(1000);
}).then(function(){
	return timerPromise(1000);
}).then(function(){
  console.log("Finished!");
}).catch(function(e){
  console.error(e);
});
//Le log "Finished!" apparait 3 secondes après, tout fonctionne

Si l'on compare ces deux exemples, la Promise créée à l'intérieur de notre fonction vient tout simplement remplacer les deux callbacks précédents par ses paramètres "resolve" et "reject", qui sont en fait des callbacks normalisés, contenu dans un objet, la promesse.

Lorsqu'une fonction retourne une promesse, on peut y appliquer notamment deux méthodes : "then" qui va être executé lorsque tout se passe bien, c'est donc l'équivalent du callback "on_success" et "catch" qui sera exécuté lors d'une erreur, l'équivalent du  "on_error" précédent.

J'espère que le concept de Promise vous est plus clair désormais !

Le but de cet article n'étaitt pas de vous expliquer les Promises en profondeur et de vous montrer tout ce qu'il est possible de faire avec, mais je sais que certains développeurs n'arrivent pas à saisir ce concept, c'est pourquoi j'ai voulu le rendre accessible à tous !

Et vous n'avez pas encore tout vu, les Promises couplées avec async/await deviennent extrèmement pratique, mais ça, c'est pour un autre article.

A bientôt sur le blog !


À propos de l'auteur

Hello, je suis Nicolas Brondin-Bernard, ingénieur web indépendant depuis 2015 passionné par le partage de d'expériences et de connaissances.

Aujourd'hui je suis aussi coach pour développeurs web juniors, tu peux me contacter sur nicolas@brondin.com, sur mon site ou devenir membre de ma newsletter pour ne jamais louper le meilleur article de la semaine et être tenu au courant de mes projets !


Photo par Ryan Franco sur Unsplash