Les promesses multiples
Objectifs
Comprendre le chaînage des promesses
Découvrir la composition des promesses
Mise en situation
Une opération asynchrone est rarement exécutée de façon isolée. En général, d'une action asynchrone de base va découler une série d'actions, elles aussi asynchrones.
Il est aussi possible qu'une action dépende du résultat de plusieurs méthodes asynchrones.
L'objet Promise
contient plusieurs méthodes qui vont faciliter le chaînage et la composition de promesses.
Méthode : Enchaînement de promesses
La méthode .then()
renvoie une promesse, c'est pourquoi il est possible de la chaîner avec .catch()
et .finally()
.
Et puisque le retour de la méthode .then()
est une promesse, rien n’empêche de chaîner ce retour avec une autre méthode .then()
.
En sachant cela, il devient possible d'exécuter une série d'actions dans un ordre défini.
var myPromise = new Promise((resolve, reject) => {
if(myAsyncFunction()) //Fonction asynchrone retournant un booléen === true
resolve("C'est un succès");
else {
reject("Une erreur est survenue");
}
});
myPromise
.then((result) => {
console.log("Résultat de myPromise : " + result);
})
.then(() => {
console.log("Promesse 2");
})
.then(() => {
console.log("Promesse 3");
});
//Résultat :
//Résultat de myPromise : C'est un succès
//Promesse 2
//Promesse 3
Si .then()
renvoie une promesse, .catch()
et .finally()
aussi.
Il est donc tout à fait possible de chaîner plusieurs .then()
, .catch()
et .finally()
.
var myPromise = new Promise((resolve, reject) => {
if(myAsyncFunction()) //Fonction asynchrone retournant un booléen
resolve("C'est un succès");
else {
reject("Une erreur est survenue");
}
});
myPromise
.then((result) => {
//Executé si resolve() est appelée dans myPromise
console.log("Résultat de myPromise : " + result);
})
.catch((error) => {
//Executé si reject() est appelée dans myPromise
console.log("Erreur de myPromise : " + error);
})
.finally(() => {
//Executé dans tous les cas après le permier then ou catch
console.log("finally method");
})
.then(() => {
//Executé après finally
console.log("then method");
});
//Résultat:
//"Résultat de myPromise : C'est un succès"
//"finally method"
//"then method"
//ou
//"Résultat de myPromise : Une erreur est survenue"
//"finally method"
//"then method"
Composition de promesses
Dans certains cas, il va être nécessaire d'attendre la résolution d'un ensemble de promesses pour continuer l’exécution du programme. Par exemple, si l'on veut télécharger l'ensemble des fichiers d'un dossier.
Méthode : Traiter toutes les promesses avec .all()
La méthode .all()
attend en paramètre un tableau de Promise
et renverra une promesse en retour. Ces promesses seront jouées selon leur ordre dans le tableau en paramètre.
La valeur retournée sera alors un tableau contenant les résultats des toutes les Promises
, dans l'ordre d'appel.
La méthode .all()
sera considérée comme fulfilled
si toutes les promesses du tableau sont fulfilled
, et inversement, comme rejected
si une seule des Promise
est rejected
.
function tryGetFile(fileName){
return new Promise(function(resolve, reject) {
var file = tryReadFile(fileName); //Méthode asynchrone pour récupérer le contenu d'un fichier
if(!!file){ // if (file === true)
resolve(file);
} else {
reject("Fichier indisponible");
}
});
}
Promise
.all([tryGetFile("File1.txt"), tryGetFile("File2.txt"), tryGetFile("File3.txt")])
.then((values) => console.log(values))
.catch((error) => console.log(error));
//Résultat:
//["Mon fichier 1", "Mon fichier 2", "Mon fichier 3"]
Complément : La plus rapide l'emporte
La méthode .race()
attend en paramètre un tableau de Promise
et renverra une promesse en retour.
À la différence de .all()
, .race()
ne renverra que la promesse résolue le plus rapidement.
const promise1 = new Promise((resolve, reject) => setTimeout(resolve, 500, 'Première'));
const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 100, 'Seconde'));
Promise
.race([promise1, promise2])
.then((result) => console.log(result)); // Les 2 sont résolues, mais promise2 est plus rapide
//Résultat:
//Seconde
Syntaxe : À retenir
Une promesse renvoie toujours une autre promesse. Par conséquent, elles peuvent être chaînées afin de définir des logiques de traitement en fonction des résultats.
Les promesses peuvent aussi être combinées. Pour attendre la résolution d'un groupe avec .
all()
, ou pour ne garder que la plus rapide avec .race()
.