Javascript : Les promises expliquées aux débutants
TLDR : Une promise est un ensemble de callbacks "normalisé" et géré nativement par Javascript !
Article publié le 27/10/2020, dernière mise à jour le 19/09/2023
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, onSuccess, onError){
if(delay < 10000){
setTimeout(onSuccess, delay);
} else {
onError("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’œil 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 exécuté 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'était 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.
Aucun commentaire pour l'instant