Promesses JavaScript
"Je promets un résultat !"
"Produire du code" désigne un code qui peut prendre du temps.
"Consommer du code" désigne un code qui doit attendre le résultat.
Une promesse est un objet qui relie le code de production et le code de consommation.
L' objet Promise représente l'achèvement ou l'échec d'une opération asynchrone et ses résultats.
Une promesse peut avoir 3 états :
| en attente | état initial |
| rejetée | opération échouée |
| remplie | opération terminée |
Exemple
// Créer un objet Promise
let myPromise = new Promise(function(myResolve, myReject) {
let result = true;
// Le code qui peut prendre du temps va ici
if (result == true) {
myResolve("OK");
} else {
myReject("Erreur");
}
});
// Utiliser then() pour afficher le résultat
myPromise.then(x => myDisplay(x), x => myDisplay(x));
Objet Promise JavaScript
Une promesse contient à la fois le code de production et les appels au code de consommation :
Syntaxe de la promesse
let myPromise = new Promise(function(myResolve, myReject) {
// "Code de production" (peut prendre du temps)
myResolve(); // quand c'est réussi
myReject(); // quand il y a une erreur
});
// "Code de consommation" (doit attendre une promesse remplie)
myPromise.then(
function(value) { /* code si réussi */ },
function(error) { /* code si erreur */ }
); Lorsque le code de production obtient le résultat, il doit appeler l'un des deux rappels :
| Quand | Appel |
|---|---|
| Succès | myResolve(valeur du résultat) |
| Erreur | myReject(objet d'erreur) |
Propriétés de l'objet Promise
Un objet Promise JavaScript peut être :
- En attente
- Rempli
- Rejeté
L'objet Promise prend en charge deux propriétés : état et résultat .
Tant qu'un objet Promise est "en attente" (en cours d'exécution), le résultat est indéfini.
Lorsqu'un objet Promise est "rempli", le résultat est une valeur.
Lorsqu'un objet Promise est "rejeté", le résultat est un objet d'erreur.
| myPromise.state | myPromise.result |
|---|---|
| "en attente" | indéfini |
| "rempli" | une valeur de résultat |
| "rejeté" | un objet d'erreur |
Vous ne pouvez pas accéder aux propriétés de la promesse état et résultat .
Vous devez utiliser une méthode Promise pour gérer les promesses.
Comment utiliser Promise
Voici comment utiliser une promesse :
myPromise.then(
function(value) { /* code si réussi */ },
function(error) { /* code si erreur */ }
); Promise.then() prend deux arguments, un rappel pour le succès et un autre pour l'échec.
Les deux sont optionnels, vous pouvez donc ajouter un rappel pour le succès ou l'échec uniquement.
Exemple
function myDisplayer(some) {
document.getElementById("demo").innerHTML = some;
}
let myPromise = new Promise(function(myResolve, myReject) {
let x = 0;
// Le code de production (cela peut prendre du temps)
if (x == 0) {
myResolve("OK");
} else {
myReject("Erreur");
}
});
myPromise.then(
function(value) {myDisplayer(value);},
function(error) {myDisplayer(error);}
);
Exemples de promesses JavaScript
Pour démontrer l'utilisation des promesses, nous allons utiliser les exemples de rappel du chapitre précédent :
- Attendre un délai
- Attendre un fichier
Attendre un délai
Exemple utilisant un rappel
setTimeout(function() { myFunction("Je t'aime !!!"); }, 3000);
function myFunction(value) {
document.getElementById("demo").innerHTML = value;
}
Exemple utilisant une promesse
let myPromise = new Promise(function(myResolve, myReject) {
setTimeout(function() { myResolve("Je t'aime !!"); }, 3000);
});
myPromise.then(function(value) {
document.getElementById("demo").innerHTML = value;
});
Attendre un fichier
Exemple utilisant un rappel
function getFile(myCallback) {
let req = new XMLHttpRequest();
req.open('GET', "mycar.html");
req.onload = function() {
if (req.status == 200) {
myCallback(req.responseText);
} else {
myCallback("Erreur : " + req.status);
}
}
req.send();
}
getFile(myDisplayer);
Exemple utilisant une promesse
let myPromise = new Promise(function(myResolve, myReject) {
let req = new XMLHttpRequest();
req.open('GET', "mycar.html");
req.onload = function() {
if (req.status == 200) {
myResolve(req.response);
} else {
myReject("Fichier non trouvé");
}
};
req.send();
});
myPromise.then(
function(value) {myDisplayer(value);},
function(error) {myDisplayer(error);}
);
JavaScript Promise.allSettled()
La méthode Promise.allSettled() renvoie une seule promesse à partir d'une liste de promesses.
Exemple
// Créer une promesse
const myPromise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 200, "Roi");
});
// Créer une autre promesse
const myPromise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, "Reine");
});
// Régler toutes
Promise.allSettled([myPromise1, myPromise2]).then((results) =>
results.forEach((x) => myDisplay(x.status)),
); Remarque
Promise.allSettled() signifie "Exécutez simplement toutes les promesses. Je me fiche des résultats".
Support des navigateurs
Promise.allSettled() est une fonctionnalité ES2020 .
ES2020 est entièrement pris en charge dans tous les navigateurs modernes depuis septembre 2020 :
| Chrome 85 | Edge 85 | Firefox 79 | Safari 14 | Opera 71 |
| Août 2020 | Août 2020 | Mars 2020 | Sept 2020 | Sept 2020 |
JavaScript Promise.withResolvers()
Promise.withResolvers() est une méthode statique qui simplifie la création et la gestion des promesses.
Promise.withResolvers() fournit un moyen plus pratique d'accéder aux fonctions resolve et reject associées à une promesse en dehors de sa fonction exécuteur.
Au lieu du modèle de constructeur traditionnel new Promise((resolve, reject) => { ... }) , Promise.withResolvers() renvoie un objet contenant :
- promise : L'instance de promesse nouvellement créée
- resolve : Une fonction pour remplir la promesse avec une valeur
- reject : Une fonction pour rejeter la promesse avec une raison (erreur)
Exemple
<p id="demo">En attente...</p>
<script>
const {promise, resolve, reject} = Promise.withResolvers();
// Vous pouvez maintenant utiliser 'resolve' et 'reject' n'importe où
// dans votre code pour contrôler l'état de 'promise'.
// Simuler un travail asynchrone
setTimeout(() => {
const success = Math.random() > 0.5;
if (success) {
resolve("Opération réussie !");
} else {
reject("Opération échouée !");
}
}, 1000);
// Mettre à jour l'interface utilisateur lorsque la promesse se termine
promise
.then((message) => {
document.getElementById("demo").innerHTML = message;
})
.catch((error) => {
document.getElementById("demo").innerHTML = error;;
});
</script>
Exemple expliqué
- Le <p id="demo"> montre initialement "En attente..."
- Après 1 seconde, la promesse se résout ou se rejette
- Le résultat est écrit dans "demo"
Le code pour simuler un travail asynchrone peut être simplifié à :
// Simuler un travail asynchrone
setTimeout(() => {
Math.random() > 0.5
? resolve("Opération réussie !")
: reject("Opération échouée !");
}, 1000);
Le code then / catch peut être simplifié à :
// Définir le texte dans then/catch, mettre à jour le DOM dans finally
promise
.then((message) => text = message)
.catch((error) => text = error)
.finally(() => {
document.getElementById("demo").innerHTML = text;
}); Exemple expliqué
- .then() ou .catch() définissent la variable texte
- .finally() s'exécute toujours en dernier, peu importe le succès ou l'échec
- Le DOM est mis à jour exactement une fois, proprement et de manière fiable
Utiliser async/await est le plus propre :
// Utiliser async/await pour gérer la promesse
(async () => {
try {
text = await promise; // Attendre la résolution
} catch (err) {
text = err; // Gérer le rejet
}
// Mettre à jour l'interface utilisateur après la fin de la promesse
document.getElementById("demo").innerHTML = text;
})(); Exemple expliqué
- async/await rend le code asynchrone semblable à du code synchrone
- Le DOM est mis à jour après que la promesse se résout ou se rejette
- L'interface utilisateur se met à jour à un seul endroit (pas d'appels innerHTML dupliqués)