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éfinition : Qu'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éthode : Cré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.
const myPromise = new Promise(/*Executeur*/(resolve, reject) => {
var result = myAsyncFunction(); //Appel à la fonction asynchrone
if(result){
//Appel de resolve() si la fonction asynchrone est considérée comme un succès (la Promise est résolue)
} else {
//Appel de reject() si la fonction asynchrone est considérée comme un échec (la Promise est rejetée)
}
});
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éthode : resolve 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.
Exemple : Vé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.
function askUsername() {
return prompt('Quel est votre nom d\'utilisateur ?')
}
function redirectUser() {
return new Promise((resolve, reject) => {
let username = askUsername()
if ('admin' === username) {
resolve()
} else {
reject()
}
})
}
function success() {
console.log('Vous êtes administrateur, vous pouvez accéder à la page')
}
function error() {
console.log('Vous n\'avez pas été reconnu comme étant un administrateur')
}
redirectUser().then(success, error)
N'hésitez pas à tester ce code, dans repl.it par exemple.
Méthode : Les 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 deresolve()
oureject()
.
Exemple : Appel XHR encapsulé dans une Promise
function getFile(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function (event) {
// Si la requête est réussie, on résout la promesse en passant la réponse en paramètre
// Sinon, on rejette la promesse en revoyant le code HTTP
if(xhr.readyState === 4 && xhr.status === 200) {
resolve(xhr.response);
} else {
reject(xhr.status);
}
};
xhr.onerror = function (err) {
// Si la requête échoue, on rejette la promesse en envoyant les infos de l'erreur
reject(err);
}
xhr.open('GET', url);
xhr.send();
});
}
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
.