重学 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 相关文章推荐
javascript 树控件 比较好用
Jun 11 Javascript
使用滤镜设置透明导致 IE 6/7/8/9 解析异常的解决方法
Apr 07 Javascript
jsp+javascript打造级连菜单的实例代码
Jun 14 Javascript
JavaScript中的Repaint和Reflow用法详解
Jul 27 Javascript
jQuery.trim() 函数及trim()用法详解
Oct 26 Javascript
javascript设计模式之模块模式学习笔记
Feb 15 Javascript
基于javascript 显式转换与隐式转换(详解)
Dec 15 Javascript
js中时间格式化的几种方法
Jul 22 Javascript
每天学点Vue源码之vm.$mount挂载函数
Mar 11 Javascript
vue下载excel的实现代码后台用post方法
May 10 Javascript
JS实现给数组对象排序的方法分析
Jun 24 Javascript
浅析TypeScript 命名空间
Mar 19 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中Collection 类的设计
2013/06/21 PHP
php json相关函数用法示例
2017/03/28 PHP
TP(thinkPHP)框架多层控制器和多级控制器的使用示例
2018/06/13 PHP
你必须知道的JavaScript 变量命名规则详解
2013/05/07 Javascript
js动态添加事件并可传参数示例代码
2013/10/21 Javascript
深入理解JavaScript系列(28):设计模式之工厂模式详解
2015/03/03 Javascript
在Node.js中使用HTTP上传文件的方法
2015/06/23 Javascript
Javascript简单改变表单元素背景的方法
2015/07/15 Javascript
jquery实现初次打开有动画效果的网页TAB切换代码
2015/09/06 Javascript
AngularJS入门教程之链接与图片模板详解
2016/08/19 Javascript
AngularJS中update两次出现$promise属性无法识别的解决方法
2017/01/05 Javascript
Nodejs之http的表单提交
2017/07/07 NodeJs
vue 本地环境跨域请求proxyTable的方法
2018/09/19 Javascript
vue多层嵌套路由实例分析
2019/03/19 Javascript
微信小程序可滑动月日历组件使用详解
2019/10/21 Javascript
javascript中contains是否包含功能实现代码(扩展字符、数组、dom)
2020/04/07 Javascript
Python最长公共子串算法实例
2015/03/07 Python
Python中List.count()方法的使用教程
2015/05/20 Python
Python标准库之Sys模块使用详解
2015/05/23 Python
python获取酷狗音乐top500的下载地址 MP3格式
2018/04/17 Python
详解python3 + Scrapy爬虫学习之创建项目
2019/04/12 Python
Python实现微信机器人的方法
2019/09/06 Python
Python实现名片管理系统
2020/02/14 Python
python安装读取grib库总结(推荐)
2020/06/24 Python
opencv 图像滤波(均值,方框,高斯,中值)
2020/07/08 Python
CSS3近阶段篇之酷炫的3D旋转透视
2016/04/28 HTML / CSS
基于HTML5代码实现折叠菜单附源码下载
2015/11/27 HTML / CSS
美国汽车交易网站:Edmunds
2016/08/17 全球购物
高中毕业生自我鉴定范文
2013/09/26 职场文书
统计员岗位职责
2013/11/14 职场文书
公司合作意向书
2014/04/01 职场文书
环卫工作汇报材料
2014/10/28 职场文书
夫妻分居协议书范文
2014/11/26 职场文书
2014年社区卫生工作总结
2014/12/18 职场文书
python 如何用map()函数创建多线程任务
2021/04/07 Python
Linux系统下MySQL配置主从分离的步骤
2022/03/21 MySQL