tnblog
首页
视频
资源
登录

forEach与async/await使用踩坑

5947人阅读 2021/5/26 19:03 总访问:69733 评论:0 收藏:0 手机
分类: uinapp

forEach与async/await使用踩坑


function test() {
 let arr = [1, 2, 3]
 arr.forEach(async item => {
  const res = await fetch(item)
  console.log(res)
 })
 console.log('end')

function fetch(x) { return new Promise((resolve, reject) => {
     resolve(x)
 })
}
 
test()

思考如上代码、我们预期结果是先输出1,2,3,然后因为等待异步结果最后输出end

但是实际上输出却是end先输出,才到1,2,3。

原因如下:

1、首先这是因为foreach是没有return返回值的(可以自己去跟下源码,foreach内部实现只是简单的回调)

2、而foreach里面的回调函数因为加了async的原因,所以默认会返回一个promise,但是因为foreach的实现并没有返回值,所以导致返回的这个promise对象没人去管了

 

首先为了保证end最后输出,我们肯定要先等待循环的返回结果因此改成如下代码


async function test() {
 let arr = [1, 2, 3]
 await arr.forEach(async item => {
  const res = await fetch(item)
  console.log(res)
 })
 console.log('end')
}

这样改之后依然行不通,原因是foreach没有返回值,所以我们必须保证循环能够有返回值,所以要将foreach改成map

async function test() {
 let arr = [1, 2, 3]
 await arr.map(async item => {
  const res = await fetch(item)
  console.log(res)
 })
 console.log('end')
}


结果依然不行,然后我们会发现其实map返回的并不是一个promise对象,而是一个包含promise对象的数组[promise, promise, promise],其中每个promise对象都是循环迭代产生的结果。
而await是处理不了数组的,它只能处理promise对象。考虑到这一点我们基本上就差不多知道如何改正了、有两种方法。

第一是将循环改成常规的遍历方式


async function test() {
 let arr = [1, 2, 3] for(let i in arr){
   const res = await fetch(arr[i])
   console.log(res)              
 }
 console.log('end')
}


第二种就比较高端了,使用Promise.all(),这是一个专门处理promise数组的方法,当async标记的箭头函数返回一个promise对象时,map方法得到的就是一个promise对象数组,然后我们
将这个数组丢给Promise.all()去依次执行,然后只需要使用await去等待执行结果,就能保证后面的end在得到结果后才会被输出,得到最终输出结果1,2,3,end



async function test() {
 let arr = [1, 2, 3]
 await Promise.all(arr.map(async item => {
  const res = await fetch(item)
  console.log(res)
 }))
 console.log('end')
}


评价

list扩展方法forEach原理(where,FirstOrDefault同理!)

//ForEach的原理就是使用循环 //委托使用循环 publicstaticvoidMyForEach<T>(thisList<T>item,Action<T...

分布式服务架构微服务架构概念的区别联系

分布式:分散压力。微服务:分散能力。当下理解分布式:不同模块部署在不同服务器上作用:分布式解决网站高并发带来问题集...

jsController中分割字符串的方法

js: varstr=OpenRule; varstrs=newArray(); strs=str.split(","); for(vari=0;i<strs.length;i++){ $(&q...

Service-stack.redis配置连接池读写分离(处理并发相关等)

配置连接池与读写分类 //写节点(主节点) List<string>writes=newList<string>(); writes.Add("123456a...

CSS相对定位绝对定位

一般相对定位和绝对定位可以配合起来使用 例如实现如下的效果 只需要在外层div设置为相对定位,在内部设置为绝对定位就...

C委托事件

1.什么是委托?  委托在C#里的意义和在现实里差不多,从字面意思理解即可。举个例子:领导委托小张去传递个文件,这就是...

asp.net core2.0 依赖注入 AddTransientAddScoped的区别

asp.net core主要提供了三种依赖注入的方式其中AddTransient与AddSingleton比较好区别AddTransient瞬时模式:每次都获取一...

Vue.js+Layer实现表格数据绑定更新

一:使用Vue.js绑定好数据与更新事件 使用v-on绑定好事件,在事件里边直接把该行数据传递进去,在更新方法里边就可以直接...

下划线、换行、回车、空格ASCII码值对照表

下划线,ASCII码95换行 , ASCII码10回车 , ASCII码13空格 , ASCII码32ASCII码表:Bin(二进制)Oct(八进制)Dec(十进制)Hex(...

数据读取器指定的"xx"不兼容。某个类型为"xx"的成员在同名的数据读取器中没有对应的列

报错的地方var result= _db.Database.SqlQuery<SMachine>(sql).FirstOrDefault();经过分析,是因为SqlQuery方法查询...

git 下载提交命令

一.先使用git clone下载一个项目 git clone '项目地址' 这里要注意: clone的项目里边会自带git的一些信息,...

微信开发四 接受用户普通消息回复消息

微信接收用户普通消息的文章可以在官方中直接看微信普通消息分类:接受用户文本消息 与 回复文本信息 注意在接收用户普通...

记忆糖的关系【阅读听力】

Link Between Memory and SugarSugar On The BrainIt’s long been understood that there is a connection between memory...

婚姻心脏健康的关系【阅读听力】

Marriage and Heart HealthPlenty of studies have found that being married is generally good for health. One study ze...

iframe自适应高度配合net core使用

去掉iframe边框frameborder="0"去掉滚动条scrolling="no"iframe 自适应高度如果内容是固定的,那么就...
走投无路 才选择了程序员
排名
40
文章
11
粉丝
3
评论
0
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术