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


Posted in Javascript onApril 15, 2019

这是重学 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 中详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
jquery 简单应用示例总结
Aug 09 Javascript
js获取日期:昨天今天和明天、后天
Jun 11 Javascript
使用JQuery库提供的扩展功能实现自定义方法
Sep 09 Javascript
JS获取图片高度宽度的方法分享
Apr 17 Javascript
Bootstrap嵌入jqGrid,使你的table牛逼起来
May 05 Javascript
js 将图片连接转换成base64格式的简单实例
Aug 10 Javascript
ES6入门教程之Iterator与for...of循环详解
May 17 Javascript
浅谈Node Inspector 代理实现
Oct 19 Javascript
用Axios Element实现全局的请求loading的方法
Mar 15 Javascript
JS实现的RC4加密算法示例
Aug 16 Javascript
微信小程序实现页面分享onShareAppMessage
Aug 12 Javascript
全面解析Vue中的$nextTick
Dec 24 Vue.js
你不知道的Vue技巧之--开发一个可以通过方法调用的组件(推荐)
Apr 15 #Javascript
详解JavaScript中的强制类型转换
Apr 15 #Javascript
一个小时快速搭建微信小程序的方法步骤
Apr 15 #Javascript
详解从0开始搭建微信小程序(前后端)的全过程
Apr 15 #Javascript
ES6知识点整理之模块化的应用详解
Apr 15 #Javascript
详解如何运行vue项目
Apr 15 #Javascript
vue单页面在微信下只能分享落地页的解决方案
Apr 15 #Javascript
You might like
php下HTTP Response中的Chunked编码实现方法
2008/11/19 PHP
PHP 页面跳转到另一个页面的多种方法方法总结
2009/07/07 PHP
php中使用getimagesize获取图片、flash等文件的尺寸信息实例
2014/04/29 PHP
php无序树实现方法
2015/07/28 PHP
PHP实现支付宝即时到账功能
2016/12/21 PHP
FireFox中textNode分片的问题
2007/04/10 Javascript
Sample script that deletes a SQL Server database
2007/06/16 Javascript
如何用js控制css中的float的代码
2007/08/16 Javascript
学习javascript,实现插入排序实现代码
2011/07/31 Javascript
js获取TreeView控件选中节点的Text和Value值的方法
2012/11/24 Javascript
基于JavaScript实现 获取鼠标点击位置坐标的方法
2013/04/12 Javascript
Javascript添加监听与删除监听用法详解
2014/12/19 Javascript
jquery右下角自动弹出可关闭的广告层
2015/05/08 Javascript
javascript的理解及经典案例分析
2016/05/20 Javascript
Node.js Streams文件读写操作详解
2016/07/04 Javascript
AngularJS 实现购物车全选反选功能
2017/10/24 Javascript
使用Sonarqube扫描Javascript代码的示例
2018/12/26 Javascript
小程序websocket心跳库(websocket-heartbeat-miniprogram)
2020/02/23 Javascript
[50:58]2018DOTA2亚洲邀请赛3月29日 小组赛A组OpTic VS Newbee
2018/03/30 DOTA
[43:32]Winstrike vs VGJ.S 2018国际邀请赛淘汰赛BO3 第一场 8.23
2018/08/24 DOTA
Python中使用PDB库调试程序
2015/04/05 Python
python3 读写文件换行符的方法
2018/04/09 Python
python re库的正则表达式入门学习教程
2019/03/08 Python
python print出共轭复数的方法详解
2019/06/25 Python
Python如何执行系统命令
2020/09/23 Python
纯CSS3实现鼠标悬停提示气泡效果
2014/02/28 HTML / CSS
html5声频audio和视频video等新特性详细说明
2012/12/26 HTML / CSS
重新定义牛仔布,100美元以下:Warp + Weft
2018/07/25 全球购物
Brasty波兰:香水、化妆品、手表网上商店
2019/04/15 全球购物
北承题目(C++)
2012/05/16 面试题
助人为乐表扬信范文
2014/01/14 职场文书
QQ空间主人寄语大全
2014/04/12 职场文书
护理目标管理责任书
2014/07/25 职场文书
专业技术职务聘任证明
2015/03/02 职场文书
《鲸》教学反思
2016/02/23 职场文书
为了顺利买到演唱会的票用Python制作了自动抢票的脚本
2021/10/16 Python