forEach中使用 async 和 await 的坑

937 阅读1分钟

一个批量操作,想要实现将每一项执行的结果(成功/失败)实时具体展示出来,在实现的时候,使用了 forEach 循环和 async、await 实现,想要实现的是串行发送请求,结果实际是并行发送的,但项目中后端的接口实现方式是不能处理并发的情况,就导致提测之后引发了bug,经过同事帮忙才找到原因。

自己验证了一下,确实是有问题

在 forEach 中 使用 async 和 await, 是不能达到同步的效果的。

forEach 本身是同步的没有问题

const arr = ['java', 'js', 'php', 'node']
arr.forEach(item => {
  console.log(item)
})
console.log('我会在 forEach 循环结束之后执行')

// 执行结果
java
js
php
node
我会在 forEach 循环结束之后执行

如果有异步任务时

const arr = ['java', 'js', 'php', 'node']
arr.forEach(item => {
  setTimeout(() => {
    console.log(item)
  }, 0);
})
console.log('settimeout之前执行')

// 执行结果
settimeout之前执行
java
js
php
node

使用 async 和await 时

const arr = ['java', 'js', 'php', 'node']
const fn = (opt) => {
  return new Promise((res, rej) => {
    res(opt)
  })
}
arr.forEach(async item => {
  console.log(`item=${item}`)
  const result = await fn({id: item});
  console.log(result)
})
console.log('settimeout之前执行')

执行结果如下图所示

Snipaste_2022-09-04_14-03-36.jpg

如果想要在循环中使用 async 和 await, 可以使用 for...of 或者 普通 for 循环代替。