重学 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 相关文章推荐
JQERY limittext 插件0.2版(长内容限制显示)
Aug 27 Javascript
一个分享按钮的插件使用介绍(可扩展,内附开发制作流程)
Sep 19 Javascript
使用Java实现简单的server/client回显功能的方法介绍
May 03 Javascript
javascript中setTimeout的问题解决方法
May 08 Javascript
微信小程序多列选择器range-key使用详解
Mar 30 Javascript
使用Angular CLI从蓝本生成代码详解
Mar 24 Javascript
express默认日志组件morgan的方法
Apr 05 Javascript
使用javascript做在线算法编程
May 25 Javascript
如何从头实现一个node.js的koa框架
Jun 17 Javascript
Vue路由对象属性 .meta $route.matched详解
Nov 04 Javascript
VUE : vue-cli中去掉路由中的井号#操作
Sep 04 Javascript
React倒计时功能实现代码——解耦通用
Sep 18 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页面间传递参数实例代码
2008/06/05 PHP
thinkphp5.0自定义验证规则使用方法
2017/11/16 PHP
实例讲解PHP表单处理
2019/02/15 PHP
PHP正则表达式函数preg_replace用法实例分析
2020/06/04 PHP
关于文本框的一些限制控制总结~~
2010/04/15 Javascript
jQuery+css实现图片滚动效果(附源码)
2013/03/18 Javascript
jQuery点击弹出下拉菜单的小例子
2013/08/01 Javascript
JavaScript获得页面base标签中url的方法
2015/04/03 Javascript
jQuery层动画定位滑动效果的方法
2015/04/30 Javascript
jquery插件jquery.LightBox.js实现点击放大图片并左右点击切换效果(附demo源码下载)
2016/02/25 Javascript
javascript检查某个元素在数组中的索引值
2016/03/30 Javascript
浅谈Jquery中Ajax异步请求中的async参数的作用
2016/06/06 Javascript
jQuery stop()用法实例详解
2016/07/28 Javascript
js放大镜放大购物图片效果
2017/01/18 Javascript
基于vue实现swipe轮播组件实例代码
2017/05/24 Javascript
浅谈一个webpack构建速度优化误区
2019/06/24 Javascript
[08:29]DOTA2每周TOP10 精彩击杀集锦vol.7
2014/06/25 DOTA
在Python中操作时间之mktime()方法的使用教程
2015/05/22 Python
Python实现按特定格式对文件进行读写的方法示例
2017/11/30 Python
python将秒数转化为时间格式的实例
2018/09/16 Python
解读python如何实现决策树算法
2018/10/11 Python
Django自定义用户表+自定义admin后台中的字段实例
2019/11/18 Python
新年福利来一波之Python轻松集齐五福(demo)
2020/01/20 Python
Django实现内容缓存实例方法
2020/06/30 Python
HTML5 input新增type属性color颜色拾取器的实例代码
2018/08/27 HTML / CSS
Hotels.com爱尔兰:全球酒店预订
2017/02/24 全球购物
中专生毕业自我鉴定
2013/11/01 职场文书
幼师自我鉴定
2014/02/01 职场文书
社区先进事迹材料
2014/05/19 职场文书
土木工程专业本科生求职信
2014/10/01 职场文书
2014年信贷员工作总结
2014/11/18 职场文书
男方家长婚礼答谢词
2015/09/29 职场文书
小学二年级语文教学反思
2016/03/03 职场文书
环境保护宣传标语大全!
2019/06/28 职场文书
python 字典和列表嵌套用法详解
2021/06/29 Python
MySQL的索引你了解吗
2022/03/13 MySQL