我正在使用async
/ await
并行发起多个api
来电:
async function foo(arr) {
const results = await Promise.all(arr.map(v => {
return doAsyncThing(v)
}))
return results
}
我知道,与loops
不同,Promise.all
executes in-parallel(也就是说,等待结果部分是并行的)。
如果其中一个元素被拒绝,则拒绝Promise.all Promise.all快速失败:如果你有四个承诺后解决 超时,并立即拒绝,然后Promise.all拒绝 立即
当我读到这篇文章时,如果我Promise.all
有5个承诺,并且第一个完成返回reject()
,则其他4个被有效取消,其承诺的resolve()
值为丢失。
还有第三种方式吗?执行是否有效并行,但单一故障不会破坏整个群体?
答案 0 :(得分:68)
虽然接受的答案中的技巧可以解决您的问题,但它是反模式的。解决带有错误的承诺并不是一种好的做法,并且有一种更简洁的方法。
你想做的是用伪语言:
fn task() {
result-1 = doAsync();
result-n = doAsync();
// handle results together
return handleResults(result-1, ..., result-n)
}
只需使用async
/ await
即可实现此目的,而无需使用Promise.all
。一个工作的例子:
console.clear();
function wait(ms, data) {
return new Promise( resolve => setTimeout(resolve.bind(this, data), ms) );
}
/**
* This will be runned in series, because
* we call a function and immediately wait for it's result,
* so this will finish in 1s.
*/
async function series() {
return {
result1: await wait(500, 'seriesTask1'),
result2: await wait(500, 'seriesTask2'),
}
}
/**
* While here we call the functions first,
* then wait for the result later, so
* this will finish in 500ms.
*/
async function parallel() {
const task1 = wait(500, 'parallelTask1');
const task2 = wait(500, 'parallelTask2');
return {
result1: await task1,
result2: await task2,
}
}
async function taskRunner(fn, label) {
const startTime = performance.now();
console.log(`Task ${label} starting...`);
let result = await fn();
console.log(`Task ${label} finished in ${ Number.parseInt(performance.now() - startTime) } miliseconds with,`, result);
}
void taskRunner(series, 'series');
void taskRunner(parallel, 'parallel');
注意:您需要一个启用了async
/ await
的浏览器来运行此代码段。
这样您只需使用try
/ catch
来处理错误,并在parallel
函数内返回部分结果。
答案 1 :(得分:34)
使用catch
表示promise解析(除非您从catch
抛出异常或手动拒绝承诺链),因此您不需要显式返回已解析的promise IIUC。
这意味着只需处理catch
错误即可实现您的目标。
如果您希望标准化拒绝处理的方式,那么您可以对所有承诺应用拒绝处理功能。
async function bar() {
await new Promise(r=> setTimeout(r, 1000))
.then(()=> console.log('bar'))
.then(()=> 'bar result');
}
async function bam() {
await new Promise((ignore, reject)=> setTimeout(reject, 2000))
.catch(()=> { console.log('bam errored'); throw 'bam'; });
}
async function bat() {
await new Promise(r=> setTimeout(r, 3000))
.then(()=> console.log('bat'))
.then(()=> 'bat result');
}
function handleRejection(p) {
return p.catch(err=> ({ error: err }));
}
async function foo(arr) {
console.log('foo');
return await Promise.all([bar(), bam(), bat()].map(handleRejection));
}
foo().then(results=> console.log('done', results));