重学 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 中ajax执行的优先级
Jun 22 Javascript
js实现简单的联动菜单效果
Aug 19 Javascript
Ionic2系列之使用DeepLinker实现指定页面URL
Nov 21 Javascript
使用 Vue.js 仿百度搜索框的实例代码
May 09 Javascript
微信小程序页面滑动屏幕加载数据效果
Nov 16 Javascript
jquery实现侧边栏左右伸缩效果的示例
Dec 19 jQuery
angular项目中bootstrap-datetimepicker时间插件的使用示例
Mar 15 Javascript
手动用webpack搭建第一个ReactApp的示例
Apr 11 Javascript
AngularJS模态框模板ngDialog的使用详解
May 11 Javascript
Vue 开发音乐播放器之歌手页右侧快速入口功能
Aug 08 Javascript
Element ui 下拉多选时新增一个选择所有的选项
Aug 21 Javascript
详解Nuxt.js中使用Element-UI填坑
Sep 06 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
ThinkPHP模板比较标签用法详解
2014/06/30 PHP
利用PHP如何写APP接口详解
2016/08/23 PHP
php array_key_exists() 与 isset() 的区别
2016/10/24 PHP
JavaScript 错误处理与调试经验总结
2010/08/10 Javascript
jquery实现metro效果示例代码
2013/09/06 Javascript
浅析Javascript使用include/require
2013/11/13 Javascript
jqgrid 表格数据导出实例
2013/11/21 Javascript
Jquery.Form 异步提交表单的简单实例
2014/03/03 Javascript
js如何判断用户是在PC端和还是移动端访问
2014/04/24 Javascript
js实现图片无缝滚动特效
2020/03/19 Javascript
JS上传图片预览插件制作(兼容到IE6)
2016/08/07 Javascript
js实现tab选项卡切换功能
2017/01/13 Javascript
基于JavaScript实现幸运抽奖页面
2020/07/05 Javascript
vuex 的简单使用
2018/03/22 Javascript
Promise.all中对于reject的处理方法
2018/08/01 Javascript
vue通过滚动行为实现从列表到详情,返回列表原位置的方法
2018/08/31 Javascript
vue项目在安卓低版本机显示空白的原因分析(两种)
2018/09/04 Javascript
js中arguments对象的深入理解
2019/05/14 Javascript
web.py中调用文件夹内模板的方法
2014/08/26 Python
Python实现的科学计算器功能示例
2017/08/04 Python
python的numpy模块安装不成功简单解决方法总结
2017/12/23 Python
Python基础之列表常见操作经典实例详解
2020/02/26 Python
Django如何实现防止XSS攻击
2020/10/13 Python
pandas针对excel处理的实现
2021/01/15 Python
大唐电信科技股份有限公司java工程师面试经历
2016/12/09 面试题
某公司C#程序员面试题笔试题
2014/05/26 面试题
社会实践心得体会
2014/01/03 职场文书
大学新生军训自我鉴定
2014/03/18 职场文书
推荐信模板
2014/05/09 职场文书
反对形式主义、官僚主义、享乐主义和奢靡之风整改措施
2014/09/17 职场文书
党员干部批评与自我批评反四风思想汇报
2014/09/21 职场文书
幼儿园法制宣传日活动总结
2014/11/01 职场文书
2014年艾滋病防治工作总结
2014/12/10 职场文书
胡雪岩故居导游词
2015/02/06 职场文书
修改MySQL的默认密码的四种小方法
2021/05/26 MySQL
5个pandas调用函数的方法让数据处理更加灵活自如
2022/04/24 Python