重学 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 相关文章推荐
JS运行耗时操作的延时显示方法
Nov 19 Javascript
检测input每次的输入是否合法遇到汉字输入就有问题
May 23 Javascript
Javascript基础教程之数据类型 (布尔型 Boolean)
Jan 18 Javascript
Angular发布1.5正式版,专注于向Angular 2的过渡
Feb 18 Javascript
复杂的javascript窗口分帧解析
Feb 19 Javascript
AngularJs  unit-testing(单元测试)详解
Sep 02 Javascript
微信小程序 video详解及简单实例
Jan 16 Javascript
javaScript+turn.js实现图书翻页效果实例代码
Feb 16 Javascript
js中document.referrer实现移动端返回上一页
Feb 22 Javascript
详解ajax的data参数错误导致页面崩溃
Apr 30 Javascript
微信小程序自定义弹出层效果
May 26 Javascript
11个Javascript小技巧帮你提升代码质量(小结)
Dec 28 Javascript
你不知道的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使用CURL实现多线程抓取网页
2015/04/30 PHP
Laravel使用swoole实现websocket主动消息推送的方法介绍
2019/10/20 PHP
php使用redis的几种常见操作方式和用法示例
2020/02/20 PHP
学习YUI.Ext 第七天--关于View&amp;JSONView
2007/03/10 Javascript
jQuery(1.3.2) 7行代码搞定跟随屏幕滚动的层
2009/05/21 Javascript
Extjs Ext.MessageBox.confirm 确认对话框详解
2010/04/02 Javascript
open 动态修改img的onclick事件示例代码
2013/11/13 Javascript
JS高级调试技巧:捕获和分析 JavaScript Error详解
2014/03/16 Javascript
JavaScript sup方法入门实例(把字符串显示为上标)
2014/10/20 Javascript
原生js和jQuery随意改变div属性style的名称和值
2014/10/22 Javascript
JavaScript使用Math.Min返回两个数中较小数的方法
2015/04/06 Javascript
Hammer.js+轮播原理实现简洁的滑屏功能
2016/02/02 Javascript
详解Javascript继承的实现
2016/03/25 Javascript
使用JavaScript获取URL中的参数(两种方法)
2016/11/16 Javascript
Bootstrap实现带暂停功能的轮播组件(推荐)
2016/11/25 Javascript
JavaScript中防止微信浏览器被整体拖动的方法
2017/08/25 Javascript
关于react-router/react-router-dom v4 history不能访问问题的解决
2018/01/08 Javascript
js中this的指向问题归纳总结
2018/11/28 Javascript
node.js域名解析实现方法详解
2019/11/05 Javascript
Vue项目中使用flow做类型检测的方法
2020/03/18 Javascript
[03:55]2014DOTA2国际邀请赛 Fnatic经理采访赢DK在情理之中
2014/07/10 DOTA
400多行Python代码实现了一个FTP服务器
2012/05/10 Python
Python reversed函数及使用方法解析
2020/03/17 Python
美国隐形眼镜网上商店:Lens.com
2019/09/03 全球购物
有趣、实用和鼓舞人心的产品:Inspire Uplift
2019/11/05 全球购物
运动会表扬稿大全
2014/01/16 职场文书
给校长的建议书400字
2014/05/15 职场文书
车贷收入证明范本
2014/09/14 职场文书
2014司机年终工作总结
2014/12/05 职场文书
高三复习计划
2015/01/19 职场文书
财务人员廉洁自律心得体会
2016/01/13 职场文书
2016年优秀党员教师先进事迹材料
2016/02/29 职场文书
2016年教师师德师风承诺书
2016/03/25 职场文书
Golang Gob编码(gob包的使用详解)
2021/05/07 Golang
python 中[0]*2与0*2的区别说明
2021/05/10 Python
java executor包参数处理功能 
2022/02/15 Java/Android