当前位置: 首页 > 编程笔记 >

重学 JS:为啥 await 不能用在 forEach 中详解

秦鸿羽
2023-03-14
本文向大家介绍重学 JS:为啥 await 不能用在 forEach 中详解,包括了重学 JS:为啥 await 不能用在 forEach 中详解的使用技巧和注意事项,需要的朋友参考一下

这是重学 JS 系列的第三篇文章,写这个系列的初衷也是为了夯实自己的 JS 基础或者了解一些之前不知道的东西。既然是重学,肯定不会从零开始介绍一个知识点,如有遇到不会的内容请自行查找资料。

不知道你有没有写过类似的代码,反正以前我是写过

function test() {
 let arr = [3, 2, 1]
 arr.forEach(async item => {
  const res = await fetch(item)
  console.log(res)
 })
 console.log('end')
}

function fetch(x) {
 return new Promise((resolve, reject) => {
  setTimeout(() => {
   resolve(x)
  }, 500 * x)
 })
}

test()

我当时期望的打印顺序是

3
2
1
end

 结果现实与我开了个玩笑,打印顺序居然是

end
1
2
3

为什么?

其实原因很简单,那就是 forEach 只支持同步代码。

我们可以参考下 Polyfill 版本的 forEach,简化以后类似就是这样的伪代码

while (index < arr.length) {
  // 也就是我们传入的回调函数
  callback(item, index)
}

从上述代码中我们可以发现,forEach 只是简单的执行了下回调函数而已,并不会去处理异步的情况。并且你在 callback 中即使使用 break 也并不能结束遍历。

怎么解决?

一般来说解决的办法有两种。

第一种是使用 Promise.all 的方式

async function test() {
 let arr = [3, 2, 1]
 await Promise.all(
  arr.map(async item => {
   const res = await fetch(item)
   console.log(res)
  })
 )
 console.log('end')
}

这样可以生效的原因是 async 函数肯定会返回一个 Promise 对象,调用 map 以后返回值就是一个存放了 Promise 的数组了,这样我们把数组传入 Promise.all 中就可以解决问题了。但是这种方式其实并不能达成我们要的效果,如果你希望内部的 fetch 是顺序完成的,可以选择第二种方式。

第一种方法是使用 for...of

async function test() {
 let arr = [3, 2, 1]
 for (const item of arr) {
  const res = await fetch(item)
  console.log(res)
 }
 console.log('end')
}

这种方式相比 Promise.all 要简洁的多,并且也可以实现开头我想要的输出顺序。

但是这时候你是否又多了一个疑问?为啥 for...of 内部就能让 await 生效呢。

因为 for...of 内部处理的机制和 forEach 不同,forEach 是直接调用回调函数,for...of 是通过迭代器的方式去遍历。

async function test() {
 let arr = [3, 2, 1]
 const iterator = arr[Symbol.iterator]()
 let res = iterator.next()
 while (!res.done) {
  const value = res.value
  const res1 = await fetch(value)
  console.log(res1)
  res = iterator.next()
 }
 console.log('end')
}

最后
以上就是本篇文章的全部内容了,如果你还有什么疑问欢迎在评论区与我互动。

我所有的系列文章都会在我的 Github 中最先更新,有兴趣的可以关注下。今年主要会着重写以下三个专栏

重学 JS
React 进阶
重写组件

以上所述是小编给大家介绍的为啥await 不能用在 forEach 中详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对小牛知识库网站的支持!

 类似资料:
  • 问题内容: 在循环中使用/ 是否有任何问题?我试图遍历文件数组和每个文件的内容。 这段代码确实有效,但是这可能会出问题吗?我让某人告诉我,您不应该在这样的高阶函数中使用/ ,所以我只是想问一下这是否有问题。 问题答案: 确保代码确实有效,但是我很确定它不会执行您期望的功能。它只会触发多个异步调用,但此后函数会立即返回。 顺序阅读 如果要顺序读取文件, 则不能使用。只需使用现代循环即可,该循环将按预

  • 我有一个webservice,它加载一些插件并调用它们的过程方法。其中一个插件获取成员列表,并确保它们都包含在MailChimp列表中。 在正常的过程代码中,这不会是一个问题。但是,httpClient上唯一可用的Post方法是PostAsync。对于Async/Await来说,我是相当陌生的,我不确定我的其余代码会有什么影响……特别是因为它涉及到我试图重用httpClient而不是为每个http

  • 我正在使用forEach循环一个nodeList。我的代码如下 此代码引发错误为 未捕获的TypeError:Array.Foreach不是函数 然而,一些较旧的浏览器还没有实现nodelist.foreach()和array.from()。但是这些限制可以通过使用array.prototype.foreach()来规避(本文档中有更多内容)。 参考:MDN

  • 问题内容: 我开始使用React Native进行编程,并且习惯于使用以下语法: 但是我不知道如何在共享包中使其与React JS和React Native兼容。我如何才能做到这一点,以使其在两个平台上都能正常工作? 谢谢! 问题答案: React Native带有Babel和一些Babel预设,而Web上的React只是与React相关的代码。 如果您今天想在网络上使用async / await

  • 本文向大家介绍详解koa2学习中使用 async 、await、promise解决异步的问题,包括了详解koa2学习中使用 async 、await、promise解决异步的问题的使用技巧和注意事项,需要的朋友参考一下 关键词:async 、await、promise 这三个东西 可以优雅的解决异步问题。在学习koa2的时候遇到了获取数据后再进行模板渲染的异步问题。在查找各种资料后成功的解决了该问

  • 我试图使用流按国籍对我的对象进行分组并打印出来。 但是它说:"不能解析方法'println"