重学 JS:为啥 await 不能用在 forEach 中详解
这是重学JS系列的第三篇文章,写这个系列的初衷也是为了夯实自己的JS基础或者了解一些之前不知道的东西。既然是重学,肯定不会从零开始介绍一个知识点,如有遇到不会的内容请自行查找资料。
不知道你有没有写过类似的代码,反正以前我是写过
functiontest(){ letarr=[3,2,1] arr.forEach(asyncitem=>{ constres=awaitfetch(item) console.log(res) }) console.log('end') } functionfetch(x){ returnnewPromise((resolve,reject)=>{ setTimeout(()=>{ resolve(x) },500*x) }) } test()
我当时期望的打印顺序是
3
2
1
end
结果现实与我开了个玩笑,打印顺序居然是
end
1
2
3
为什么?
其实原因很简单,那就是forEach只支持同步代码。
我们可以参考下Polyfill版本的forEach,简化以后类似就是这样的伪代码
while(index从上述代码中我们可以发现,forEach只是简单的执行了下回调函数而已,并不会去处理异步的情况。并且你在callback中即使使用break也并不能结束遍历。
怎么解决?
一般来说解决的办法有两种。
第一种是使用Promise.all的方式
asyncfunctiontest(){ letarr=[3,2,1] awaitPromise.all( arr.map(asyncitem=>{ constres=awaitfetch(item) console.log(res) }) ) console.log('end') }这样可以生效的原因是async函数肯定会返回一个Promise对象,调用map以后返回值就是一个存放了Promise的数组了,这样我们把数组传入Promise.all中就可以解决问题了。但是这种方式其实并不能达成我们要的效果,如果你希望内部的fetch是顺序完成的,可以选择第二种方式。
第一种方法是使用for...of
asyncfunctiontest(){ letarr=[3,2,1] for(constitemofarr){ constres=awaitfetch(item) console.log(res) } console.log('end') }这种方式相比Promise.all要简洁的多,并且也可以实现开头我想要的输出顺序。
但是这时候你是否又多了一个疑问?为啥for...of内部就能让await生效呢。
因为for...of内部处理的机制和forEach不同,forEach是直接调用回调函数,for...of是通过迭代器的方式去遍历。
asyncfunctiontest(){ letarr=[3,2,1] constiterator=arr[Symbol.iterator]() letres=iterator.next() while(!res.done){ constvalue=res.value constres1=awaitfetch(value) console.log(res1) res=iterator.next() } console.log('end') }最后
以上就是本篇文章的全部内容了,如果你还有什么疑问欢迎在评论区与我互动。我所有的系列文章都会在我的Github中最先更新,有兴趣的可以关注下。今年主要会着重写以下三个专栏
重学JS
React进阶
重写组件以上所述是小编给大家介绍的为啥await不能用在forEach中详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。