JavaScript 循环:如何处理 async/await

如何串行或者并行运行异步循环?编程

在使用循环处理异步的魔法以前,咱们先来看下咱们是怎么处理同步循环的。数组

同步循环

好久之前我写的循环是这样的:promise

for (var i = 0; i < array.length; i++) {
  var item = array[i];
  //  do something with item
}

后来 JavaScript 提供了不少新的特性,如今咱们会更倾向于用下面这种写法:异步

array.forEach((item) => {
  //  do something with item
})

在开发过程可能会有这么一种需求,咱们须要在循环中异步处理 item,那么能够怎么作呢?async

异步循环

如何在循环中使用 await?咱们试着写一个异步函数,而后 await 每一次循环任务。函数

async function processArray(array) {
  array.forEach(() => {
    //  define synchronous anonymous function
    //  it will throw error here
    await func(item)
  });
}

这个代码会抛出一个错误,由于咱们不能在同步方法中使用 await, processArray 确实是异步函数,可是 array.forEach 里的匿名函数是同步的。spa

1. 不要等待结果

要处理这个问题,咱们能够把这个匿名函数定义为异步的:code

async function processArray(array) {
  array.forEach(() => {
    await delayedLog(item)
  });
  console.log('Done!');
}

可是这样的话 forEach 方法就至关于异步的了,不会等待遍历完全部的 item,例以下面这段代码:对象

function delay () {
  return new Promise(resolve => setTimeout(resolve, 300));
}

async function delayedLog(item) {
  //  notice that we can await a function that returns promise
  await delay();
  //  log item only after a delay 
  console.log(item);
}

async function processArray(array) {
  array.forEach(() => {
    await delayedLog(item)
  });
  console.log('Done!');
}

processArray([1, 2, 3]);

将会输出:blog

Done!
1
2
3

若是你不须要等待这个循环完成,这样就已经能够了。可是大部分状况咱们仍是须要等待这个循环完成才进行以后的操做。

2. 串行遍历

要等待全部的结果返回,咱们仍是要回到老式的 for 循环写法:

async function processArray(array) {
  for (const item of arr) {
    await delayedLog(item);
  }
  console.log('Done!');
}

最后的结果符合咱们的预期:

1
2
3
Done!

上面这段的遍历代码是串行执行的,咱们也能够把它换成并行的。

3. 并行遍历

咱们能够稍微更改上面的代码来编程并行的:

async function processArray(array) {
  //  map() 方法建立一个新数组,其结果是该数组中的每一个元素都调用一个提供的函数后返回的结果。
  //  async 修饰的方法返回值是一个promise对象,所以下面map的返回值就是一个promise列表
  const promiseArr = array.map(delayedLog);
  //  wait until all promises are resolved
  await Promise.all(promiseArr);
  console.log('Done!');
}

(注意:对于特别大的数组不建议使用这种写法,太多的并行任务会加剧 CPU 和内存的负荷)

 转自:https://zhuanlan.zhihu.com/p/31000936

相关文章
相关标签/搜索