Comment puis-je modifier le code suivant afin que les deux opérations asynchrones soient déclenchées et se voient offrir la possibilité de s'exécuter simultanément?
const value1 = await getValue1Async();
const value2 = await getValue2Async();
// use both values
Dois-je faire quelque chose comme ça?
const p1 = getValue1Async();
const p2 = getValue2Async();
const value1 = await p1;
const value2 = await p2;
// use both values
Je pense que cela devrait fonctionner:
const [value1, value2] = await Promise.all([getValue1Async(),getValue2Async()]);
Vous trouverez ci-dessous un exemple plus détaillé au cas où cela vous aiderait à comprendre:
const promise1 = async() => {
return 3;
}
const promise2 = async() => {
return 42;
}
const promise3 = async() => {
return 500;
// emulate an error
// throw "something went wrong...";
}
const f1 = async() => {
try {
// returns an array of values
const results = await Promise.all([promise1(), promise2(), promise3()]);
console.log(results);
console.log(results[0]);
console.log(results[1]);
console.log(results[2]);
// assigns values to individual variables through 'array destructuring'
const [value1, value2, value3] = await Promise.all([promise1(), promise2(), promise3()]);
console.log(value1);
console.log(value2);
console.log(value3);
} catch (err) {
console.log("there was an error: " + err);
}
}
f1();
Assurez-vous de gérer correctement les rejets et de pouvoir utiliser Promises.all () en toute sécurité sans faire face à des rejets non gérés. (Édition: clarification par discussion: pas l'erreur unhandled rejection
, mais simplement les rejets qui ne sont pas traités par le code. Promise.all()
lèvera le premier rejet de promesse et ignorera le reste).
Dans l'exemple ci-dessous, un tableau de [[erreur, résultats], ...] est renvoyé pour faciliter le traitement des résultats et/ou des erreurs.
let myTimeout = (ms, is_ok) =>
new Promise((resolve, reject) =>
setTimeout(_=> is_ok ?
resolve(`ok in ${ms}`) :
reject(`error in ${ms}`),
ms));
let handleRejection = promise => promise
.then((...r) => [null, ...r])
.catch(e => [e]);
(async _=> {
let res = await Promise.all([
myTimeout(100, true),
myTimeout(200, false),
myTimeout(300, true),
myTimeout(400, false)
].map(handleRejection));
console.log(res);
})();
Vous pouvez jeter de l'intérieur d'un catch () pour ne plus attendre (et ignorer les résultats du reste). Cependant, vous ne pouvez le faire qu'une fois par bloc try/catch, il est donc nécessaire de conserver un drapeau et de le contrôler aucune erreur non gérée ne se produit.
let myTimeout = (ms, is_ok) =>
new Promise((resolve, reject) =>
setTimeout(_=> is_ok ?
resolve(`ok in ${ms}`) :
reject(`error in ${ms}`),
ms));
let has_thrown = false;
let handleRejection = promise => promise
.then((...r) => [null, ...r])
.catch(e => {
if (has_thrown) {
console.log('not throwing', e);
} else {
has_thrown = 1;
throw e;
}
});
(async _=> {
try {
let res = await Promise.all([
myTimeout(100, true),
myTimeout(200, false),
myTimeout(300, true),
myTimeout(400, false)
].map(handleRejection));
console.log(res);
} catch(e) {
console.log(e);
}
console.log('we are done');
})();
const wait = (ms, data) => new Promise( resolve => setTimeout(resolve, ms, data) )
const reject = (ms, data) => new Promise( (r, reject) => setTimeout(reject, ms, data) )
const e = e => 'err:' + e
const l = l => (console.log(l), l)
;(async function parallel() {
let task1 = reject(500, 'parallelTask1').catch(e).then(l)
let task2 = wait(2500, 'parallelTask2').catch(e).then(l)
let task3 = reject(1500, 'parallelTask3').catch(e).then(l)
console.log('WAITING')
;[task1, task2, task3] = [await task1, await task2, await task3]
console.log('FINISHED', task1, task2, task3)
})()
Comme cela a été souligné dans d’autres réponses, une promesse rejetée peut donner lieu à une exception non gérée.
Celui-ci .catch(e => e)
est un joli petit truc qui capte l’erreur et la transmet dans la chaîne, permettant ainsi à la promesse de devenir resolve
au lieu de rejecting
.
Si vous trouvez ce code ES6 moche, voyez plus convivial ici .