| [ Web Proxy ] |
| Viewing: https://developer.mozilla.org/fr/docs/Web/JavaScript/Guide/Using_promises#composition | [Back] [Original] |
Get to know MDN better
Cette page a t traduite partir de l'anglais par la communaut. Vous pouvez contribuer en rejoignant la communaut francophone sur MDN Web Docs.
Une promesse est un objet (Promise) qui reprsente la compltion ou l'chec d'une opration asynchrone. La plupart du temps, on consomme des promesses et c'est donc ce que nous verrons dans la premire partie de ce guide pour ensuite expliquer comment les crer.
En rsum, une promesse est un objet qui est renvoy et auquel on attache des callbacks plutt que de passer des callbacks une fonction. Ainsi, au lieu d'avoir une fonction qui prend deux callbacks en arguments :
function faireQqcALAncienne(successCallback, failureCallback) {
console.log("C'est fait");
// russir une fois sur deux
if (Math.random() > 0.5) {
successCallback("Russite");
} else {
failureCallback("chec");
}
}
function successCallback(rsultat) {
console.log("L'opration a russi avec le message : " + rsultat);
}
function failureCallback(erreur) {
console.error("L'opration a chou avec le message : " + erreur);
}
faireQqcALAncienne(successCallback, failureCallback);
On aura une fonction qui renvoie une promesse et on attachera les callbacks sur cette promesse :
function faireQqc() {
return new Promise((successCallback, failureCallback) => {
console.log("C'est fait");
// russir une fois sur deux
if (Math.random() > 0.5) {
successCallback("Russite");
} else {
failureCallback("chec");
}
});
}
const promise = faireQqc();
promise.then(successCallback, failureCallback);
ou encore :
faireQqc().then(successCallback, failureCallback);
Cette dernire forme est ce qu'on appelle un appel de fonction asynchrone. Cette convention possde diffrents avantages dont le premier est le chanage.
la diffrence des imbrications de callbacks, une promesse apporte certaines garanties :
then seront appels, y compris aprs le succs ou l'chec de l'opration asynchronethen plusieurs fois, ils seront alors excuts l'un aprs l'autre selon l'ordre dans lequel ils ont t insrs.Un besoin frquent est d'excuter deux ou plus d'oprations asynchrones les unes la suite des autres, avec chaque opration qui dmarre lorsque la prcdente a russi et en utilisant le rsultat de l'tape prcdente. Ceci peut tre ralis en crant une chane de promesses.
La mthode then() renvoie une nouvelle promesse, diffrente de la premire :
const promise = faireQqc();
const promise2 = promise.then(successCallback, failureCallback);
ou encore :
const promise2 = faireQqc().then(successCallback, failureCallback);
La deuxime promesse (promise2) indique l'tat de compltion, pas uniquement pour faireQqc() mais aussi pour le callback qui lui a t pass (successCallback ou failureCallback) qui peut aussi tre une fonction asynchrone qui renvoie une promesse. Lorsque c'est le cas, tous les callbacks ajouts promise2 forment une file derrire la promesse renvoye par successCallback ou failureCallback.
Autrement dit, chaque promesse reprsente l'tat de compltion d'une tape asynchrone au sein de cette succession d'tapes.
Auparavant, l'enchanement de plusieurs oprations asynchrones dclenchait une pyramide dantesque de callbacks :
faireQqc(function (result) {
faireAutreChose(
result,
function (newResult) {
faireUnTroisiemeTruc(
newResult,
function (finalResult) {
console.log("Rsultat final :" + finalResult);
},
failureCallback,
);
},
failureCallback,
);
}, failureCallback);
Grce des fonctions plus modernes et aux promesses, on attache les callbacks aux promesses qui sont renvoyes. On peut ainsi construire une chane de promesses :
faireQqc()
.then(function (result) {
return faireAutreChose(result);
})
.then(function (newResult) {
return faireUnTroisiemeTruc(newResult);
})
.then(function (finalResult) {
console.log("Rsultat final : " + finalResult);
})
.catch(failureCallback);
Les arguments passs then sont optionnels. La forme catch(failureCallback) est un alias plus court pour then(null, failureCallback). Ces chanes de promesses sont parfois construites avec des fonctions flches :
faireQqc()
.then((result) => faireAutreChose(result))
.then((newResult) => faireUnTroisiemeTruc(newResult))
.then((finalResult) => {
console.log("Rsultat final : " + finalResult);
})
.catch(failureCallback);
Attention :
Cela implique que les fonctions asynchrones renvoient toutes des promesses, sinon les callbacks ne pourront tre chans et les erreurs ne seront pas interceptes (les fonctions flches ont une valeur de retour implicite si les accolades ne sont pas utilises : () => x est synonyme de () => { return x; }).
Il est possible de chaner de nouvelles actions aprs un rejet, c'est--dire un catch. C'est utile pour accomplir de nouvelles actions aprs qu'une action ait chou dans la chaine. Par exemple :
new Promise((resolve, reject) => {
console.log("Initial");
resolve();
})
.then(() => {
throw new Error("Something failed");
console.log("Do this");
})
.catch(() => {
console.error("Do that");
})
.then(() => {
console.log("Do this whatever happened before");
});
Cela va produire la sortie suivante :
Initial Do that Do this whatever happened before
Notez que le texte "Do this" n'est pas affich car l'erreur "Something failed" a produit un rejet.
Dans les exemples prcdents, failureCallback tait prsent trois fois dans la pyramide de callbacks et une seule fois, la fin, dans la chane des promesses :
faireQqc()
.then((result) => faireAutreChose(result))
.then((newResult) => faireUnTroisiemeTruc(newResult))
.then((finalResult) => console.log("Rsultat final : " + finalResult))
.catch(failureCallback);
En fait, ds qu'une exception est leve, la chane de promesses utilisera le premier catch() ou onRejected disponible. Ce fonctionnement est assez proche de ce qu'on peut trouver pour du code synchrone :
try {
const result = syncFaireQqc();
const newResult = syncFaireQqcAutre(result);
const finalResult = syncFaireUnTroisiemeTruc(newResult);
console.log("Rsultat final : " + finalResult);
} catch (error) {
failureCallback(error);
}
Cette symtrie entre le code asynchrone et le code synchrone atteint son paroxysme avec le couple d'oprateurs async/await d'ECMAScript 2017:
async function toto() {
try {
const result = await faireQqc();
const newResult = await faireQqcAutre(result);
const finalResult = await faireUnTroisiemeTruc(newResult);
console.log("Rsultat final : " + finalResult);
} catch (error) {
failureCallback(error);
}
}
Ce fonctionnement est construit sur les promesses et faireQqc() est la mme fonction que celle utilise dans les exemples prcdents.
Les promesses permettent de rsoudre les problmes de cascades infernales de callbacks notamment en interceptant les diffrentes erreurs (exceptions et erreurs de programmation). Ceci est essentiel pour obtenir une composition fonctionnelle des oprations asynchrones.
Lorsqu'une promesse est rompue/rejete, un des deux vnements suivants est envoy au niveau de la porte globale (window ou Worker si le script est utilis dans un worker) :
rejectionhandledCet vnement est envoy lorsqu'une promesse est rompue et aprs que le rejet ai t trait par la fonction reject associe la promesse.
unhandledrejectionCet vnement est envoy lorsque la promesse est rompue et qu'aucune fonction n'a t dfinie pour grer le rejet de la promesse.
Dans les deux cas, l'vnement (dont le type est PromiseRejectionEvent) aura deux proprits :
Grer ces vnements permet d'avoir une ultime mthode pour grer le rejet des promesses. Cela peut notamment s'avrer utile pour le dbogage. Ces vnements sont dclenchs au niveau global et permettent ainsi d'intercepter les erreurs pour chaque contexte (fentre ou worker)
window.addEventListener(
"unhandledrejection",
(event) => {
// Examiner la ou les promesse(s) qui posent problme en debug
// Nettoyer ce qui doit l'tre quand a se produit en rel
},
false,
);
Il est possible de crer un objet Promise grce son constructeur. Et mme si, idalement, cela ne devrait pas tre ncessaire, certaines API fonctionnent toujours avec des callbacks passs en arguments. C'est notamment le cas de la mthode setTimeout() :
setTimeout(() => saySomething("10 seconds passed"), 10 * 1000);
Si on mlange des callbacks et des promesses, cela sera problmatique. Si saySomething choue ou contient des erreurs, rien n'interceptera l'erreur.
Pour ces fonctions, la meilleure pratique consiste les envelopper dans des promesses au plus bas niveau possible et de ne plus les appeler directement :
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
wait(10 * 1000)
.then(() => saySomething("10 seconds"))
.catch(failureCallback);
Le constructeur Promise prend en argument une fonction et nous permet de la convertir manuellement en une promesse. Ici, vu que setTimeout n'choue pas vraiment, on laisse de ct la gestion de l'chec.
Promise.resolve() et Promise.reject() sont des mthodes qui permettent de crer des promesses dj tenues ou rompues.
Promise.all() et Promise.race() sont deux outils de composition qui permettent de mener des oprations asynchrones en parallle.
On peut lancer des oprations en parallles et attendre qu'elles soient toutes finies de cette faon :
Promise.all([func1(), func2(), func3()]).then(
([resultat1, resultat2, resultat3]) => {
/* o on utilise resultat1/2/3 */
},
);
Il est possible de construire une composition squentielle de la faon suivante :
[func1, func2].reduce((p, f) => p.then(f), Promise.resolve());
Dans ce fragment de code, on rduit un tableau de fonctions asynchrones en une chane de promesse quivalente : Promise.resolve().then(func1).then(func2);
On peut galement accomplir cela avec une fonction de composition rutilisable :
const applyAsync = (acc, val) => acc.then(val);
const composeAsync =
(...funcs) =>
(x) =>
funcs.reduce(applyAsync, Promise.resolve(x));
La fonction composeAsync accepte autant de fonctions que ncessaire comme arguments et renvoie une nouvelle fonction qui prend une valeur initiale pour la passer travers ces tapes de compositions. Cette faon de faire garantit que les fonctions, qu'elles soient synchrones ou asynchrones, sont excutes dans le bon ordre :
const transformData = composeAsync(func1, asyncFunc1, asyncFunc2, func2);
transformData(data);
Avec ECMAScript 2017, on peut obtenir une composition squentielle plus simplement avec les oprateurs await/async :
let result;
for (const f of [func1, func2, func3]) {
result = await f(result);
}
Pour viter de mauvaises surprises, les fonctions passes then() ne seront jamais appeles de faon synchrone, y compris lorsqu'il s'agit d'une promesse dj rsolue :
Promise.resolve().then(() => console.log(2));
console.log(1); // 1, 2
En fait, la fonction passe then() est place dans une file de micro-tches qui sont excutes lorsque cette file est vide la fin de la boucle d'vnements JavaScript :
var wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
wait().then(() => console.log(4));
Promise.resolve()
.then(() => console.log(2))
.then(() => console.log(3));
console.log(1); // 1, 2, 3, 4
Promise.then()async/awaitCette page a t modifie le 4 dc. 2025 par les contributeurices du MDN.
Certaines parties de ce contenu sont protges par le droit d'auteur 19982026 des contributeurs individuels de mozilla.org. Contenu disponible sous une licence Creative Commons.
| Web Proxy Viewer | New URL | Original Page |