如何在Javascript中并行运行async/await

如何在Javascript中并行运行async/await,javascript,async-await,Javascript,Async Await,最后,async/await将很快出现在除IE之外的所有主流浏览器中。 因此,现在我们可以开始使用async/await编写更可读的代码,但有一个缺点。很多人使用async Wait时都是这样: const userResponse = await fetchUserAsync(); const postsResponse = await fetchPostsAsync(); const responses = await Promise.all([ fetchUserAsync(), f

最后,
async
/
await
将很快出现在除IE之外的所有主流浏览器中。 因此,现在我们可以开始使用
async
/
await
编写更可读的代码,但有一个缺点。很多人使用async Wait时都是这样:

const userResponse = await fetchUserAsync();
const postsResponse = await fetchPostsAsync();
const responses = await Promise.all([
 fetchUserAsync(),
 fetchPostsAsync(),
]);

const userResponse = responses[0];
const postsResponse = responses[1];
虽然这段代码是可读的,但它有一个问题,它以串联方式运行函数,在用户的获取完成之前,它不会开始获取帖子。解决方案很简单,我们需要并行获取资源

所以我想做的是(用伪语言):


你可以这样写:

const userResponse = await fetchUserAsync();
const postsResponse = await fetchPostsAsync();
const responses = await Promise.all([
 fetchUserAsync(),
 fetchPostsAsync(),
]);

const userResponse = responses[0];
const postsResponse = responses[1];
这很容易,对吧?但有一个陷阱<代码>承诺。所有都有快速失败行为,这意味着一旦其中一个承诺被拒绝,它将立即拒绝。您可能想要一个更健壮的解决方案,我们负责处理任何回迁的拒绝。幸运的是,有一个解决方案,只需使用
async
/
wait
即可实现,而无需使用
Promise.all
。一个有效的例子:

console.clear();
函数等待(毫秒、数据){
返回新承诺(resolve=>setTimeout(resolve.bind(this,data),ms));
}
/** 
*这将以串联方式运行,因为
*我们调用函数并立即等待结果,
*所以这将在1s内完成。
*/
异步函数系列(){
返回{
结果1:等待等待(500,'seriesTask1'),
结果2:等待等待(500,'seriesTask2'),
}
}
/** 
*这里我们先调用函数,
*然后等待结果,所以
*这将在500毫秒内完成。
*/
异步函数并行(){
const task1=wait(500,'parallelstask1');
const task2=wait(500,'parallelTask2');
返回{
结果1:等待任务1,
结果2:等待任务2,
}
}
异步函数taskRunner(fn,标签){
const startTime=performance.now();
log(`Task${label}start…`);
让结果=等待fn();
log(`Task${label}在${Number.parseInt(performance.now()-startTime)}毫秒内完成,带,`,result);
}
void taskRunner(系列,'系列');
void taskRunner(parallel,“parallel”);
/* 
*结果将是:
*任务系列开始。。。
*任务并行启动。。。
*任务并行在500毫秒内完成,{“result1”:“parallelTask1”,“result2”:“parallelTask2”}
*任务系列在1001毫秒内完成,{“result1”:“seriesTask1”,“result2”:“seriesTask2”}

*/
实际上我也做了同样的事情。通过使用Promissions,然后使用Promission.all在最后对它们进行同步,您可以执行许多并发请求,但要确保在完成之前返回所有结果

请参见最后一个示例:

如果您对Promise.all的fail fast行为和解构分配语法没有异议:

const [userResponse, postsResponse] = await Promise.all([
  fetchUserAsync(),
  fetchPostsAsync(),
]);

伪代码可以编写如下:

fn async task() {
  result-1 = doAsync();
  result-2 = doAsync();
  result-n = doLongAsync();
  try{
  // handle results together
  combinedResult = handleResults(await result-1, await result-2);
  lastResult = handleLastResult(await result-n);
  }
  catch(err){
   console.error(err)
  }

}
结果1、结果2和结果n将并行运行。 combinedResult和lastResult也将并行运行。 但是,一旦结果-1和结果-2可用,将返回combinedResult值,即返回handleResults函数;一旦结果-n可用,将返回lastResult值,即返回handleResults函数


希望这有帮助首先,你的代码是阻塞代码吗

如果是,请记住javascript是单线程的,因此不能同时运行两个同步代码,例如两个循环(for或while)

但是,通过使用Web Workers,我可以在通用Web Workers中执行函数,而不使用单独的js文件

setInterval(()=>{console.log(“非阻塞”+Math.random())},900)
log(“开始在web Worker中并行阻止代码”)
控制台时间(“阻塞”)
genericWorker(窗口,[“块CPU”,函数(块){
block(10000)//此blockCpu函数定义如下
return“\n\nbla bla\n”//这在已解决的承诺中被捕获
}]).然后(函数(结果){
控制台。时间结束(“阻止”)
日志(“阻塞代码结束”,结果)
})
.catch(函数(错误){console.log(错误)})
/*如果Web Worker不使用文件,它将从Blob创建该文件
@cb_context,回调函数参数所在的上下文,例如:window
@cb,[“fn_name1”,“fn_name2”,函数(fn1,fn2){}]
将执行回调,您可以将其他函数传递给该cb
*/
函数genericWorker(cb_上下文,cb){
返回新承诺(功能(解决、拒绝){
if(!cb | |!Array.isArray(cb))
返回拒绝(“无效数据”)
var callback=cb.pop()
var函数=cb
if(typeof callback!=“function”| | functions.some((fn)=>{返回cb_上下文的类型[fn]!=“function”}))
return reject(`回调或某些参数:(${functions.toString()})不是函数`)
if(functions.length>0&&!cb_上下文)
返回拒绝(“上下文未定义”)
callback=fn\u string(callback)//要执行的回调
functions=functions.map((fn_name)=>{返回fn_字符串(cb_上下文[fn_name]))
var worker_file=window.URL.createObjectURL(新Blob([“self.addEventListener('message',function(e){var bb={};var args=[];for(fn of e.data.functions){bb[fn.name]=新函数(fn.args,fn.body);args.push(fn.name)};var回调=新函数(e.data.callback.args,e.data.callback.body);args=args.map(函数(fn_name){返回bb[fn_name]};var result=callback.apply(null,args);self.postMessage(result);},false)]
var worker=新的worker(worker\u文件)
postMessage({callback:callback,functions:functions})
worker.addEventListener('error',函数(error){return reject(error.message)})
worker.addEventListener('message',函数(e){
解析(如数据),worker.terminate()
},错)
//从函数到字符串,以及其名称、参数和正文
功能