据我所知,在ES7/ES2016中,在代码中放置多个await将类似于用promise链接.then(),这意味着它们将一个接一个地执行,而不是并行执行。例如,我们有以下代码:
await someCall();
await anotherCall();
我是否正确理解只有当someCall()完成时才会调用另一个otherCall()?并行调用它们最优雅的方式是什么?
我想在Node中使用它,所以也许有一个异步库的解决方案?
编辑:我对这个问题中提供的解决方案不满意:由于异步生成器中的非并行等待承诺,所以速度变慢,因为它使用生成器,我问的是一个更通用的用例。
您可以等待Promise.all():
await Promise.all([someCall(), anotherCall()]);
要存储结果:
let [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);
请注意,Promise.all很快就会失败,这意味着一旦提供给它的一个承诺被拒绝,那么整个承诺就会被拒绝。
const happy=(v,ms)=>new Promise((resolve)=>setTimeout(()=>resolve(v),ms))const sad=(v,ms)=>new Promise((_,reject)=>setTimeout(()=>reject(v),ms))承诺。所有([快乐('快乐',100),悲伤('悲伤',50)]).then(console.log).catch(console.log)//“sad”
相反,如果您希望等待所有承诺兑现或拒绝,则可以使用Promise.allSettled。请注意,Internet Explorer本机不支持此方法。
const happy=(v,ms)=>new Promise((resolve)=>setTimeout(()=>resolve(v),ms))const sad=(v,ms)=>new Promise((_,reject)=>setTimeout(()=>reject(v),ms))承诺。一切都已解决([快乐('快乐',100),悲伤('悲伤',50)]).then(console.log)//[{“status”:“已完成”,“value”:“快乐”},{“status”:“拒绝”,“reason”:“悲伤”}]
注意:如果您使用Promise.在拒绝发生之前完成的所有操作都不会回滚,因此您可能需要注意这种情况。例如如果你有5个动作,4个快速,1个慢速和慢速拒绝。这4个操作可能已经执行,因此您可能需要回滚。在这种情况下,考虑使用Promise.allSettled,同时它将提供哪些操作失败和哪些操作未失败的确切细节。
这可以通过Promise.allSettled()实现,它类似于Promise.all(),但没有快速失败行为。
async function Promise1() {
throw "Failure!";
}
async function Promise2() {
return "Success!";
}
const [Promise1Result, Promise2Result] = await Promise.allSettled([Promise1(), Promise2()]);
console.log(Promise1Result); // {status: "rejected", reason: "Failure!"}
console.log(Promise2Result); // {status: "fulfilled", value: "Success!"}
注意:这是一个边缘功能,浏览器支持有限,因此我强烈建议为该功能添加polyfill。
没有Promise.all()还有另一种方法可以并行执行:
首先,我们有两个功能来打印数字:
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);
});
}
这是顺序的:
async function oneByOne() {
const number1 = await printNumber1();
const number2 = await printNumber2();
}
//Output: Number1 is done, Number2 is done
这是平行的:
async function inParallel() {
const promise1 = printNumber1();
const promise2 = printNumber2();
const number1 = await promise1;
const number2 = await promise2;
}
//Output: Number2 is done, Number1 is done
更新:
最初的答案使正确处理拒绝承诺变得困难(在某些情况下是不可能的)。正确的解决方案是使用Promise.all:
const [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);
原答覆:
只需确保在等待其中一个函数之前调用这两个函数:
// Call both functions
const somePromise = someCall();
const anotherPromise = anotherCall();
// Await both promises
const someResult = await somePromise;
const anotherResult = await anotherPromise;
您可以调用多个异步函数,而无需等待它们。这将并行执行它们。执行此操作时,将返回的Promise保存在变量中,并在某个时刻单独或使用Promise.all()等待它们,然后处理结果。
还可以使用try…包装函数调用。。。catch处理单个异步操作的失败并提供回退逻辑。
下面是一个示例:观察日志,在单个异步函数开始执行时打印的日志会立即打印,即使第一个函数需要5秒才能解析。
函数someLongFunc(){return new Promise((resolve,reject)=>{console.log('执行功能1')setTimeout(分辨率,5000)})}函数另一个LongFunc(){return new Promise((resolve,reject)=>{console.log('执行功能2')setTimeout(分辨率,5000)})}异步函数main(){让某个LongFuncPromise,另一个LongFunc Promiseconst start=Date.now()尝试{someLongFuncPromise=someLongFunc()}捕获(ex){console.error('功能1期间出现问题')}尝试{anotherLongFuncPromise=另一个LongFunc()}捕获(ex){console.error('功能2期间出现问题')}等待某人LongFuncPromise等待另一个LongFuncPromiseconst totalTime=Date.now()-开始console.log('执行完成时间',totalTime)}main()
在我的例子中,我有几个任务要并行执行,但我需要对这些任务的结果做一些不同的事情。
function wait(ms, data) {
console.log('Starting task:', data, ms);
return new Promise(resolve => setTimeout(resolve, ms, data));
}
var tasks = [
async () => {
var result = await wait(1000, 'moose');
// do something with result
console.log(result);
},
async () => {
var result = await wait(500, 'taco');
// do something with result
console.log(result);
},
async () => {
var result = await wait(5000, 'burp');
// do something with result
console.log(result);
}
]
await Promise.all(tasks.map(p => p()));
console.log('done');
输出:
Starting task: moose 1000
Starting task: taco 500
Starting task: burp 5000
taco
moose
burp
done
(异步函数(){功能等待(毫秒,数据){console.log('启动任务:',数据,毫秒);return new Promise(resol=>setTimeout(resolve,ms,data));}var任务=[异步()=>{var result=等待等待(1000,'moose');//做些有结果的事console.log(结果);},异步()=>{var result=等待等待(500,'taco');//做些有结果的事console.log(结果);},异步()=>{var result=等待等待(5000,'burp');//做些有结果的事console.log(结果);}]await Promise.all(tasks.map(p=>p()));console.log(“one”);})();