forEach和for中使用await返回的结果?

async function test(){
  // [3,2,1].forEach( async (v)=>{
  //   let res = await fetch(v)
  //   console.log(res)
  // })
  // console.log('end')
  let arr = [3,2,1]
  for(var i=0;i<arr.length;i++){
    let res = await fetch(arr[i])
    console.log(res)
  }
  console.log('end')
}
function fetch(x){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      console.log('setTimeout',x)
      resolve(x)
    },5 * x)// setTimeout设置的时间不考虑?
  })
}

test()

使用for遍历为什么输出的结果是

3
2
1
end
阅读 2k
3 个回答

道理很简单,因为for循环会被await影响,而forEach你传递的闭包所返回的promise并不会被等待。
也就是说,使用闭包看起来是这样执行的

fetch(3)
fetch(2)
fetch(1)

各个异步事件其实是独立的,并不会互相影响

而for循环展开则是这样执行的

await fetch(3)
await fetch(2)
await fetch(1)

一些新人可能会觉得forEach比for更高级,但是forEach其实是无法完成一些操作的,例如中断循环(break),continue循环,循环中不容易异步任务控制(本问题),我的建议是只在一些迭代器代码的尾部使用forEach,常规的业务代码为了控制方便,依然使用for来进行循环。

另外:如果真的需要并发也不应该用forEach,应该使用.map

const result = await Promise.all(arr.map(e=>fetch(e)))

总的来说使用forEach需要一定的学习,要注意不要滥用,map方法同理,不要将.map方法作为forEach使用。

相当于3个await吧,你这个先是15ms输出3,再隔10ms输出2,最后隔开5ms输出1。

  async function test(){
  let arr = [3,2,1]
  console.time('test')
  for(var i=0;i<arr.length;i++){
    let res = await fetch(arr[i])
    console.log(res)
  }
  console.timeEnd('test')
  console.log('end')
}

整个用时再30ms以上

forEach 并不能搭配 async/await 使用变成同步执行,就是说 fetch(3),fetch(2),fetch(1) 是几乎同时执行的,然后再按照内部的 timeout 时间去输出,所以结果会是:

end
setTimeout 1
1
setTimeout 2
2
setTimeout 3
3

for 可以搭配 async/awiat 使循环变成同步执行,也就是说等待 fetch(3) 执行完之后才会接着执行 fetch(2), fetch(2) 执行完之后才会再执行 fetch(1)。所以执行结果会变成:

setTimeout 3
3
setTimeout 2
2
setTimeout 1
1
end
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题