Les promesses

Objectifs

  • Découvrir ce qu'est une promesse JavaScript

  • Créer une promesse avec l'objet Promise

  • Connaître les mécanismes de base d'une promesse

Mise en situation

Depuis la démocratisation de la norme ES6, de plus en plus d'API JavaScript utilisent les promesses pour gérer leur code asynchrone. Il est donc important de comprendre leur fonctionnement et de connaître les avantages qu'elles apportent au développement.

DéfinitionQu'est-ce qu'une promesse ?

Une promesse JavaScript est un objet Promise qui représente l'état d'une fonction asynchrone, c'est-à-dire si l'opération asynchrone est "En cours", "Valide", "En erreur".

Cet objet Promise va nous permettre de définir le comportement (du code) à exécuter en fonction de l'état de la promesse.

Une analogie simple serait celle du candidat à une élection :

Un candidat a défini que :

  • S'il est élu, il appliquera son programme.

  • S'il est disqualifié, il quittera la politique.

Le candidat a fait une promesse sur le résultat de l'élection. Il a défini les comportements pour les cas de succès, d'échec ou d'erreur de cette promesse.

Une promesse JavaScript est bâtie exactement de la même façon. À la différence que la promesse JavaScript garantit l'exécution du code.

MéthodeCréer une promesse avec l'objet Promise

Bien que le concept soit plus ancien, ES6 introduit l'objet Promise qui va permettre de créer simplement des promesses, sans API tierces.

1
const myPromise = new Promise(/*Executeur*/(resolve, reject) => { 
2
    var result = myAsyncFunction(); //Appel à la fonction asynchrone
3
4
    if(result){
5
        //Appel de resolve() si la fonction asynchrone est considérée comme un succès (la Promise est résolue)
6
    } else {
7
        //Appel de reject() si la fonction asynchrone est considérée comme un échec (la Promise est rejetée)
8
    }
9
});

Le constructeur de Promise attend en paramètre une fonction, appelée exécuteur. À cette fonction, on passera 2 arguments : resolve et reject.

Si la fonction est un succès, on appellera resolve ; si c'est un échec, on appellera reject.

La fonction exécuteur sera exécutée immédiatement, sans attendre que l'objet soit construit.

Méthoderesolve et reject

Les fonctions resolve() et reject() permettent de modifier l'état de la promesse. Elle passera ainsi d'un état pending à un état fulfilled avec resolve ou rejected avec reject.

Si une des fonctions resolve() ou reject() est appelée, les autres appels aux fonctions resolve() ou reject() seront ignorés. Une fois en état fulfilled ou rejected, une promesse ne pourra plus changer d'état.

En pratique, il faudra créer des fonctions qui renverront des promesses.

ExempleVérifier l'identité d'un utilisateur

On souhaite mettre en place une fonction au sein de notre application qui permettra de vérifier qu'un utilisateur est bien administrateur avant d'accéder à une page. Pour cela, on lui demande d'indiquer son nom d'utilisateur au moyen de la fonction askUsername. Il s'agira ici de notre fonction asynchrone : tant que l'utilisateur n’interagit pas, rien ne se passe.

Une fois cette réponse obtenue, on vérifie la réponse : s'il a indiqué "admin", alors on considère que la promesse est résolue, sinon on considère qu'elle sera rejetée.

Au moyen de la méthode then, que nous aborderons plus tard, on indique ce qui doit être exécuté en cas de résolution ou de rejet de la promesse.

1
function askUsername() {
2
  return prompt('Quel est votre nom d\'utilisateur ?')
3
}   
4
5
function redirectUser() {
6
  return new Promise((resolve, reject) => {
7
    let username = askUsername()
8
9
    if ('admin' === username) {
10
      resolve()
11
    } else {
12
      reject()
13
    }
14
  })
15
}
16
17
function success() {
18
  console.log('Vous êtes administrateur, vous pouvez accéder à la page')
19
}
20
21
function error() {
22
  console.log('Vous n\'avez pas été reconnu comme étant un administrateur')
23
}
24
25
redirectUser().then(success, error)

N'hésitez pas à tester ce code, dans repl.it par exemple.

MéthodeLes propriétés d'une promesse

L'objet Promise contient deux propriétés internes, state et result :

  • La propriété state va donner une indication sur l'état de la promesse : pending (en cours), fulfilled (résolue), rejected (rejetée).

  • La propriété result va contenir la valeur définie par le développeur comme argument de resolve() ou reject().

ExempleAppel XHR encapsulé dans une Promise

1
function getFile(url) {
2
    return new Promise(function (resolve, reject) {
3
        var xhr = new XMLHttpRequest();
4
    
5
        xhr.onreadystatechange = function (event) {
6
            // Si la requête est réussie, on résout la promesse en passant la réponse en paramètre
7
            // Sinon, on rejette la promesse en revoyant le code HTTP
8
            if(xhr.readyState === 4 && xhr.status === 200) {
9
                resolve(xhr.response);
10
            } else {
11
                reject(xhr.status);
12
            }
13
        };
14
    
15
        xhr.onerror = function (err) {
16
            // Si la requête échoue, on rejette la promesse en envoyant les infos de l'erreur
17
            reject(err); 
18
        }
19
    
20
        xhr.open('GET', url);
21
        xhr.send();
22
    });
23
}

SyntaxeÀ retenir

  • Avec ES6, l'objet Promise est devenu incontournable dans la programmation asynchrone JavaScript.

  • L'état d'une promesse est stocké dans sa propriété state. La valeur de cette propriété va permettre de définir les actions à effectuer en cas de réussite (resolve) ou d'échec (reject) d'une fonction asynchrone.

  • Le résultat de ces fonctions sera ensuite stocké dans la propriété result.

Complément