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éthodeEnchaî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.

1
var myPromise = new Promise((resolve, reject) => {
2
    if(myAsyncFunction()) //Fonction asynchrone retournant un booléen === true
3
        resolve("C'est un succès");
4
    else {
5
        reject("Une erreur est survenue");
6
    }
7
});
8
9
myPromise
10
    .then((result) => {
11
        console.log("Résultat de myPromise : " + result);
12
    })
13
    .then(() => {
14
        console.log("Promesse 2");
15
    })
16
    .then(() => {
17
        console.log("Promesse 3");
18
    });
19
20
//Résultat :
21
//Résultat de myPromise : C'est un succès
22
//Promesse 2
23
//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() .

1
var myPromise = new Promise((resolve, reject) => {
2
    if(myAsyncFunction()) //Fonction asynchrone retournant un booléen
3
        resolve("C'est un succès");
4
    else {
5
        reject("Une erreur est survenue");
6
    }
7
});
8
9
myPromise
10
    .then((result) => {
11
        //Executé si resolve() est appelée dans myPromise
12
        console.log("Résultat de myPromise : " + result);
13
    })
14
    .catch((error) => {
15
        //Executé si reject() est appelée dans myPromise
16
        console.log("Erreur de myPromise : " + error);
17
    })
18
    .finally(() => {
19
        //Executé dans tous les cas après le permier then ou catch
20
        console.log("finally method");
21
    })
22
    .then(() => {
23
        //Executé après finally
24
        console.log("then method");
25
    });
26
27
//Résultat:
28
//"Résultat de myPromise : C'est un succès"
29
//"finally method"
30
//"then method"
31
//ou
32
//"Résultat de myPromise : Une erreur est survenue"
33
//"finally method"
34
//"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éthodeTraiter 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.

1
function tryGetFile(fileName){
2
    return new Promise(function(resolve, reject) {
3
        var file = tryReadFile(fileName); //Méthode asynchrone pour récupérer le contenu d'un fichier
4
        if(!!file){ // if (file === true)
5
            resolve(file);
6
        } else {
7
            reject("Fichier indisponible");
8
        }
9
    }); 
10
}
11
12
Promise
13
    .all([tryGetFile("File1.txt"), tryGetFile("File2.txt"), tryGetFile("File3.txt")])
14
    .then((values) => console.log(values))
15
    .catch((error) => console.log(error));
16
17
//Résultat: 
18
//["Mon fichier 1", "Mon fichier 2", "Mon fichier 3"]

ComplémentLa 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.

1
const promise1 = new Promise((resolve, reject) => setTimeout(resolve, 500, 'Première'));
2
3
const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 100, 'Seconde'));
4
5
Promise
6
    .race([promise1, promise2])
7
    .then((result) => console.log(result)); // Les 2 sont résolues, mais promise2 est plus rapide
8
9
//Résultat: 
10
//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().