Javascript 并行调用异步/等待函数
据我所知,在ES7/ES2016中,在代码中放置多个Javascript 并行调用异步/等待函数,javascript,node.js,asynchronous,ecmascript-6,babeljs,Javascript,Node.js,Asynchronous,Ecmascript 6,Babeljs,据我所知,在ES7/ES2016中,在代码中放置多个wait,将类似于使用承诺链接。然后(),这意味着它们将一个接一个地执行,而不是并行执行。例如,我们有以下代码: await someCall(); await anotherCall(); 我是否正确理解只有在someCall()完成时才会调用anotherCall()?什么是并行调用它们的最优雅方式 我想在Node中使用它,所以可能有一个使用异步库的解决方案 编辑:我对这个问题中提供的解决方案不满意,因为它使用生成器,我想问一个更通用的用
wait
,将类似于使用承诺链接。然后()
,这意味着它们将一个接一个地执行,而不是并行执行。例如,我们有以下代码:
await someCall();
await anotherCall();
我是否正确理解只有在someCall()
完成时才会调用anotherCall()
?什么是并行调用它们的最优雅方式
我想在Node中使用它,所以可能有一个使用异步库的解决方案
编辑:我对这个问题中提供的解决方案不满意,因为它使用生成器,我想问一个更通用的用例。您可以在
Promise.all()上等待:
要存储结果,请执行以下操作:
let [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);
请注意,Promise.all
很快就会失败,这意味着一旦提供给它的一个承诺被拒绝,那么整个东西就会被拒绝
consthappy=(v,ms)=>新承诺((解析)=>setTimeout(()=>resolve(v,ms))
const sad=(v,ms)=>新承诺((u,拒绝)=>设置超时(()=>拒绝(v,ms))
承诺。所有([快乐('happy',100),悲伤('sad',50)])
.then(console.log).catch(console.log)/“sad”
TL;DR
使用Promise.all
对于并行函数调用,当错误发生时,应答行为不正确
首先,一次执行所有异步调用并获取所有Promise
对象。其次,在Promise
对象上使用wait
。这样,当您等待第一个Promise
解析时,其他异步调用仍在进行中。总的来说,您将只等待最慢的异步调用。例如:
// 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
JSbin示例:
警告:只要第一个wait
调用发生在所有异步调用之后,那么wait
调用是在同一行还是在不同的行上并不重要。见JohnnyHK的评论
更新:此答案在错误处理中的时间根据的不同而不同,它不会在错误发生时抛出错误,但在所有承诺执行后抛出错误。
我将结果与@jonny的提示进行比较:[result1,result2]=Promise
const correctAsync500ms=()=>{
返回新承诺(解决=>{
setTimeout(resolve,500,'correct500msResult');
});
};
常数校正异步100ms=()=>{
返回新承诺(解决=>{
setTimeout(resolve,100,'correct100msResult');
});
};
常量拒绝异步100ms=()=>{
返回新承诺((解决、拒绝)=>{
setTimeout(拒绝,100,'reject100msError');
});
};
const asyninarray=async(fun1,fun2)=>{
常量标签='testasync functions in array';
试一试{
控制台。时间(标签);
常数p1=fun1();
常数p2=fun2();
常量结果=[等待p1,等待p2];
控制台。时间结束(标签);
}捕获(e){
控制台错误('error is',e);
控制台。时间结束(标签);
}
};
const asyncInPromiseAll=async(fun1,fun2)=>{
const label='test async functions with Promise.all';
试一试{
控制台。时间(标签);
让[value1,value2]=等待承诺;
控制台。时间结束(标签);
}捕获(e){
控制台错误('error is',e);
控制台。时间结束(标签);
}
};
(异步()=>{
group('async functions without error');
log('无错误的异步函数:start')
等待asyncInArray(correctAsync500ms,correctAsync100ms);
等待asyncInPromiseAll(correctAsync500ms,correctAsync100ms);
console.groupEnd();
group('async functions with error');
log('异步函数出现错误:start')
等待asyncInArray(校正Async500ms,拒绝Async100ms);
等待asyncInPromiseAll(校正异步500ms,拒绝异步100ms);
console.groupEnd();
})();代码>我投票支持:
await Promise.all([someCall(), anotherCall()]);
请注意调用函数时,可能会导致意外结果:
// Supposing anotherCall() will trigger a request to create a new User
if (callFirst) {
await someCall();
} else {
await Promise.all([someCall(), anotherCall()]); // --> create new User here
}
但以下操作总是触发创建新用户的请求
// Supposing anotherCall() will trigger a request to create a new User
const someResult = someCall();
const anotherResult = anotherCall(); // ->> This always creates new User
if (callFirst) {
await someCall();
} else {
const finalResult = [await someResult, await anotherResult]
}
更新:
最初的答案使正确处理拒绝承诺变得困难(在某些情况下是不可能的)。正确的解决方法是使用承诺。所有:
await Promise.all([someCall(), anotherCall()]);
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;
我创建了一个助手函数waitAll,也许它可以让它更甜美。
它现在只在nodejs中工作,而在浏览器chrome中不工作
//const parallel = async (...items) => {
const waitAll = async (...items) => {
//this function does start execution the functions
//the execution has been started before running this code here
//instead it collects of the result of execution of the functions
const temp = [];
for (const item of items) {
//this is not
//temp.push(await item())
//it does wait for the result in series (not in parallel), but
//it doesn't affect the parallel execution of those functions
//because they haven started earlier
temp.push(await item);
}
return temp;
};
//the async functions are executed in parallel before passed
//in the waitAll function
//const finalResult = await waitAll(someResult(), anotherResult());
//const finalResult = await parallel(someResult(), anotherResult());
//or
const [result1, result2] = await waitAll(someResult(), anotherResult());
//const [result1, result2] = await parallel(someResult(), anotherResult());
我创建了一些不同的解决承诺的方法,并取得了成果。查看有效的选项可能会有所帮助
编辑:根据客户的评论编辑要点内容
// Simple gist to test parallel promise resolution when using async / await
function promiseWait(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(true);
}, time);
});
}
async function test() {
return [
await promiseWait(1000),
await promiseWait(5000),
await promiseWait(9000),
await promiseWait(3000),
]
}
async function test2() {
return {
'aa': await promiseWait(1000),
'bb': await promiseWait(5000),
'cc': await promiseWait(9000),
'dd': await promiseWait(3000),
}
}
async function test3() {
return await {
'aa': promiseWait(1000),
'bb': promiseWait(5000),
'cc': promiseWait(9000),
'dd': promiseWait(3000),
}
}
async function test4() {
const p1 = promiseWait(1000);
const p2 = promiseWait(5000);
const p3 = promiseWait(9000);
const p4 = promiseWait(3000);
return {
'aa': await p1,
'bb': await p2,
'cc': await p3,
'dd': await p4,
};
}
async function test5() {
return await Promise.all([
await promiseWait(1000),
await promiseWait(5000),
await promiseWait(9000),
await promiseWait(3000),
]);
}
async function test6() {
return await Promise.all([
promiseWait(1000),
promiseWait(5000),
promiseWait(9000),
promiseWait(3000),
]);
}
async function test7() {
const p1 = promiseWait(1000);
const p2 = promiseWait(5000);
const p3 = promiseWait(9000);
return {
'aa': await p1,
'bb': await p2,
'cc': await p3,
'dd': await promiseWait(3000),
};
}
let start = Date.now();
test().then((res) => {
console.log('Test Done, elapsed', (Date.now() - start) / 1000, res);
start = Date.now();
test2().then((res) => {
console.log('Test2 Done, elapsed', (Date.now() - start) / 1000, res);
start = Date.now();
test3().then((res) => {
console.log('Test3 Done, elapsed', (Date.now() - start) / 1000, res);
start = Date.now();
test4().then((res) => {
console.log('Test4 Done, elapsed', (Date.now() - start) / 1000, res);
start = Date.now();
test5().then((res) => {
console.log('Test5 Done, elapsed', (Date.now() - start) / 1000, res);
start = Date.now();
test6().then((res) => {
console.log('Test6 Done, elapsed', (Date.now() - start) / 1000, res);
});
start = Date.now();
test7().then((res) => {
console.log('Test7 Done, elapsed', (Date.now() - start) / 1000, res);
});
});
});
});
});
});
/*
Test Done, elapsed 18.006 [ true, true, true, true ]
Test2 Done, elapsed 18.009 { aa: true, bb: true, cc: true, dd: true }
Test3 Done, elapsed 0 { aa: Promise { <pending> },
bb: Promise { <pending> },
cc: Promise { <pending> },
dd: Promise { <pending> } }
Test4 Done, elapsed 9 { aa: true, bb: true, cc: true, dd: true }
Test5 Done, elapsed 18.008 [ true, true, true, true ]
Test6 Done, elapsed 9.003 [ true, true, true, true ]
Test7 Done, elapsed 12.007 { aa: true, bb: true, cc: true, dd: true }
*/
//使用async/await时测试并行承诺解析的简单要点
功能承诺等待(时间){
返回新承诺((解决、拒绝)=>{
设置超时(()=>{
决心(正确);
},时间);
});
}
异步函数测试(){
返回[
等待承诺人等待(1000),
等待承诺人等待(5000),
等待承诺等待(9000),
等待承诺等待(3000),
]
}
异步函数test2(){
返回{
“aa”:等待承诺等待(1000),
“bb”:等待承诺等待(5000),
“cc”:等待承诺等待(9000),
“dd”:等待承诺等待(3000),
}
}
异步函数test3(){
返回等待{
“aa”:承诺等待(1000),
“bb”:承诺等待(5000),
“抄送”:承诺等待(9000),
“dd”:承诺等待(3000),
}
}
异步函数test4(){
常数p1=承诺等待(1000);
常数p2=承诺等待(5000);
常数p3=承诺等待(9000);
常数p4=承诺等待(3000);
返回{
“aa”:等待p1,
“bb”:等待p2,
“cc”:等待p3,
“dd”:等待p4,
};
}
异步函数test5(){
回报等待承诺([
等待承诺人等待(1000),
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
// 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
*/
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
// create a queue object with concurrency 2
var q = async.queue(function(task, callback) {
console.log('Hello ' + task.name);
callback();
}, 2);
// assign a callback
q.drain = function() {
console.log('All items have been processed');
};
// add some items to the queue
q.push({name: 'foo'}, function(err) {
console.log('Finished processing foo');
});
q.push({name: 'bar'}, function (err) {
console.log('Finished processing bar');
});
// add some items to the queue (batch-wise)
q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function(err) {
console.log('Finished processing item');
});
// add some items to the front of the queue
q.unshift({name: 'bar'}, function (err) {
console.log('Finished processing bar');
});