Autant que je sache, dans ES7/ES2016, l'insertion de plusieurs await
dans le code fonctionnera de manière similaire à l'enchaînement de .then()
avec des promesses, ce qui signifie qu'ils s'exécuteront les uns après les autres plutôt que de façon parallèle. Donc, par exemple, nous avons ce code:
await someCall();
await anotherCall();
Dois-je bien comprendre que anotherCall()
ne sera appelé que lorsque someCall()
sera terminé? Quelle est la manière la plus élégante de les appeler en parallèle?
Je veux l'utiliser dans Node, alors peut-être qu'il existe une solution avec une bibliothèque asynchrone?
EDIT: Je ne suis pas satisfait de la solution fournie dans cette question: Ralentissement dû à une attente non parallèle des promesses dans les générateurs asynchrones , car il utilise des générateurs et je demande un cas d'utilisation plus général .
Vous pouvez attendre sur Promise.all()
:
await Promise.all([someCall(), anotherCall()]);
Pour stocker les résultats:
let [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);
TL; DR
Utilisez Promise.all
pour les appels de fonction parallèles, les comportements de réponse ne sont pas corrects lorsque l'erreur se produit.
Tout d'abord, exécutez tous les appels asynchrones à la fois et obtenez tous les objets Promise
. Deuxièmement, utilisez await
sur les objets Promise
. Ainsi, pendant que vous attendez que le premier Promise
soit résolu, les autres appels asynchrones sont toujours en cours. Dans l'ensemble, vous n'attendrez que le plus long appel asynchrone. Par exemple:
// Begin first call and store promise without waiting
const someResult = someCall();
// Begin second call and store promise without waiting
const anotherResult = anotherCall();
// Now we await for both results, whose async processes have already been started
const finalResult = [await someResult, await anotherResult];
// At this point all calls have been resolved
// Now when accessing someResult| anotherResult,
// you will have a value instead of a promise
Exemple JSbin: http://jsbin.com/xerifanima/edit?js,console
Avertissement: Peu importe que les appels await
se trouvent sur la même ligne ou sur des lignes différentes, tant que le premier await
appel survient après tous les appels asynchrones. Voir le commentaire de JohnnyHK.
Mise à jour: Cette réponse a un timing différent dans la gestion des erreurs selon le réponse de @ bergi , elle le fait PAS élimine l'erreur lorsque l'erreur se produit, mais après l'exécution de toutes les promesses. Je compare le résultat avec le conseil de @ jonny: [result1, result2] = Promise.all([async1(), async2()])
, vérifiez l'extrait de code suivant.
const correctAsync500ms = () => {
return new Promise(resolve => {
setTimeout(resolve, 500, 'correct500msResult');
});
};
const correctAsync100ms = () => {
return new Promise(resolve => {
setTimeout(resolve, 100, 'correct100msResult');
});
};
const rejectAsync100ms = () => {
return new Promise((resolve, reject) => {
setTimeout(reject, 100, 'reject100msError');
});
};
const asyncInArray = async (fun1, fun2) => {
const label = 'test async functions in array';
try {
console.time(label);
const p1 = fun1();
const p2 = fun2();
const result = [await p1, await p2];
console.timeEnd(label);
} catch (e) {
console.error('error is', e);
console.timeEnd(label);
}
};
const asyncInPromiseAll = async (fun1, fun2) => {
const label = 'test async functions with Promise.all';
try {
console.time(label);
let [value1, value2] = await Promise.all([fun1(), fun2()]);
console.timeEnd(label);
} catch (e) {
console.error('error is', e);
console.timeEnd(label);
}
};
(async () => {
console.group('async functions without error');
console.log('async functions without error: start')
await asyncInArray(correctAsync500ms, correctAsync100ms);
await asyncInPromiseAll(correctAsync500ms, correctAsync100ms);
console.groupEnd();
console.group('async functions with error');
console.log('async functions with error: start')
await asyncInArray(correctAsync500ms, rejectAsync100ms);
await asyncInPromiseAll(correctAsync500ms, rejectAsync100ms);
console.groupEnd();
})();
Mise à jour:
La réponse initiale rend difficile (et dans certains cas impossible) le traitement correct des rejets de promesses. La solution correcte consiste à utiliser Promise.all
:
const [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);
Réponse originale:
Assurez-vous d’appeler les deux fonctions avant d’attendre l’une ou l’autre:
// Call both functions
const somePromise = someCall();
const anotherPromise = anotherCall();
// Await both promises
const someResult = await somePromise;
const anotherResult = await anotherPromise;
Il y a une autre manière sans Promise.all () de le faire en parallèle:
Premièrement, nous avons 2 fonctions pour imprimer des numéros:
function printNumber1() {
return new Promise((resolve,reject) => {
setTimeout(() => {
console.log("Number1 is done");
resolve(10);
},1000);
});
}
function printNumber2() {
return new Promise((resolve,reject) => {
setTimeout(() => {
console.log("Number2 is done");
resolve(20);
},500);
});
}
C'est séquentiel:
async function oneByOne() {
const number1 = await printNumber1();
const number2 = await printNumber2();
}
//Output: Number1 is done, Number2 is done
C'est parallèle:
async function inParallel() {
const promise1 = printNumber1();
const promise2 = printNumber2();
const number1 = await promise1;
const number2 = await promise2;
}
//Output: Number2 is done, Number1 is done
J'ai créé n Gist en testant différentes façons de résoudre les promesses, avec des résultats. Il peut être utile de voir les options qui fonctionnent.
// A generic test function that can be configured
// with an arbitrary delay and to either resolve or reject
const test = (delay, resolveSuccessfully) => new Promise((resolve, reject) => setTimeout(() => {
console.log(`Done ${ delay }`);
resolveSuccessfully ? resolve(`Resolved ${ delay }`) : reject(`Reject ${ delay }`)
}, delay));
// Our async handler function
const handler = async () => {
// Promise 1 runs first, but resolves last
const p1 = test(10000, true);
// Promise 2 run second, and also resolves
const p2 = test(5000, true);
// Promise 3 runs last, but completes first (with a rejection)
// Note the catch to trap the error immediately
const p3 = test(1000, false).catch(e => console.log(e));
// Await all in parallel
const r = await Promise.all([p1, p2, p3]);
// Display the results
console.log(r);
};
// Run the handler
handler();
/*
Done 1000
Reject 1000
Done 5000
Done 10000
*/
Bien que définir p1, p2 et p3 ne les exécute pas strictement en parallèle, ils ne retardent aucune exécution et vous pouvez intercepter les erreurs contextuelles avec un catch.