Les promesses en Javascript sont des objets représentant l’état d’une opération asynchrone. Elles ont été créées en 2015 par l’ES6 pour rendre la gestion des fonctions successives plus claire.
C’est un des éléments les plus importants du développement web en javascript: les promesses. Je vous en donne ici une définition, ainsi que les caractéristiques.
Qu’est-ce qu’une promesse en javascript ?
Une promesse est un objet qui représente l’état d’une opération asynchrone. Une promesse peut être dans l’un des trois états : en attente (pending), résolue (fulfilled) ou rejetée (rejected). Les promesses sont utilisées pour manipuler des opérations asynchrones de manière plus lisible et gérable.
Elles permettent de gérer plus facilement l’asynchronicité. La possible de renseigner les erreurs est aussi importante.
Imaginons que vous commandez un café dans un café. On vous donne un ticket (la promesse) que vous pouvez utiliser pour récupérer votre café (résolution de la promesse) une fois qu’il est prêt. Néanmoins, il pourrait ne jamais être prêt ou bien qu’il y ait un problème. Dans cette allégorie, ce même ticket vous avertirait. (rejet de la promesse).
La syntaxe des promesses
D’abord, on définit la promesse:
const maPromesse = new Promise((resolve, reject) => {
setTimeout(() => {
const operationReussie = true;
if (operationReussie) {
resolve('Opération réussie');
} else {
reject('Opération échouée');
}
}, 2000);
});
resolve
etreject
sont des fonctions fournies par le constructeurPromise
.resolve
: à appeler lorsque l’opération asynchrone est réussie.reject
: à appeler lorsque l’opération asynchrone échoue.
Si c’est resolve qui est exécuté, ce sera une réussite et la valeur de retour pourra être captée par .then et si c’est reject, c’est une erreur qui pourra être captée par .catch (voir point suivant).
Ensuite, on va utiliser les méthodes de cette promesse pour l’exploiter. Par exemple:
maPromesse
.then(resultat => {
console.log(`Résultat : ${resultat}`);
})
.catch(erreur => {
console.log(`Erreur : ${erreur}`);
})
.finally(() => {
console.log('Promesse terminée');
});
Ici, notre promesse renverra automatiquement:
Résultat : Opération réussie
Promesse terminée
La valeur de la fonction passée en paramètre de then est celle qui est passée en paramètre à resolve. Si on avait mis « operationReussie = false », on aurait:
Erreur : Opération échouée
Promesse terminée
La valeur de la fonction passée en paramètre de catch est celle qui est passée en paramètre à reject.
Fonctionnalités
Chaînage des promesses
Vous pouvez mettre à la suite plusieurs promesses, qui s’exécuteront successivement, avec .then.
Une erreur interrompra la chaîne, amenant à la méthode catch la plus proche. Exemple:
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.log('Erreur : ', error));
Capture d’erreurs
La méthode « catch » permet de capturer les erreurs et exceptions: si une promesse est rejetée, le contrôle passe au bloc catch le plus proche. Vous pouvez par exemple faire s’afficher une erreur spécifiant le moment de l’erreur (« console log(« erreur à tel moment ») »). Il y a aussi différents types d’erreurs:
fetch('https://api.example.com/data')
.then(response => response.json())
.catch(NetworkError => {
// Gérer l'erreur réseau
})
.catch(SyntaxError => {
// Gérer l'erreur de syntaxe
});
Finally
La méthode finally
s’exécutera qu’une promesse soit résolue ou rejetée. Elle peut être par exemple utilisée pour placer du code de nettoyage.
fetch('https://api.example.com/data')
.then(response => response.json())
.catch(error => console.error('Erreur :', error))
.finally(() => {
console.log('Nettoyage des ressources');
});
La différence avec une fonction
L’un des intérêts des promesses, quand il y a choix, est de rendre le code plus facile à lire/gérer. Par exemple, imaginons qu’on veuille afficher 3 énoncés après 3 fois après 1s. On aurait trois fonctions:
function op1(callback) {
setTimeout(() => {
console.log("Fin de op1");
callback();
}, 1000);
}
function op2(callback) {
setTimeout(() => {
console.log("Fin de op2");
callback();
}, 1000);
}
function op3() {
setTimeout(() => {
console.log("Fin de op3");
}, 1000);
}
op1(() => {
op2(() => {
op3();
});
});
function op1() {
return new Promise((resolve) => {
setTimeout(() => {
console.log("Fin de op1");
resolve();
}, 1000);
});
}
function op2() {
return new Promise((resolve) => {
setTimeout(() => {
console.log("Fin de op2");
resolve();
}, 1000);
});
}
function op3() {
return new Promise((resolve) => {
setTimeout(() => {
console.log("Fin de op3");
resolve();
}, 1000);
});
}
op1()
.then(op2)
.then(op3);
La notation sous forme de promesse est plus facile à maintenir.
Les états d’une promesse en javascript
Les promesses ont trois états:
- Pending: La promesse est en cours d’exécution.
- Fulfilled: L’opération a réussi et la promesse a une valeur de retour.
- Rejected: L’opération a échoué et la promesse a une raison d’échec.
Vous pouvez attacher des callbacks pour ces états :
.then()
est appelé quand la promesse est résolue..catch()
est appelé quand la promesse est rejetée.
Méthodes particulières
Promise.all
La méthode Promise.all
prend un tableau de promesses et retourne une nouvelle promesse. Cette promesse résultante ne sera résolue que lorsque toutes les promesses dans le tableau seront résolues. Si l’une des promesses est rejetée, la promesse résultante est également rejetée immédiatement.
Promise.all([promise1, promise2, promise3])
.then(values => {
console.log('Toutes les promesses sont résolues:', values);
})
.catch(error => {
console.log('Une des promesses a été rejetée:', error);
});
Promise.race
À l’inverse, Promise.race
prend également un tableau de promesses mais retourne une nouvelle promesse qui se résout ou se rejette dès que la première promesse du tableau est résolue ou rejetée.
Cela permet notamment de stopper un ensemble de promesses si l’une d’elles met trop longtemps à se résoudre. Cela permet aussi
Promise.race([promise1, promise2, promise3])
.then(value => {
console.log('La première promesse résolue:', value);
})
.catch(error => {
console.log('La première promesse rejetée:', error);
});
Pour aller plus loin:
- Le cours de Grafikart : https://grafikart.fr/tutoriels/javascript-promise-2067
- Explications de Pierre Giraud : https://www.pierre-giraud.com/javascript-apprendre-coder-cours/promesse-promise/