关于在foreach中使用await 或者其他异步问题处理

701 阅读3分钟

我正在参加「掘金·启航计划」

背景

前几天在项目中有遇到一种情况,就是后台返回的一个树形结构的分类数的数据给到前端我这边,不过有需要调两个接口,一个接口是获取标签的tab,可以看成是一级的分类,一个接口就是用来获取所有的子集,因为业务所致,所以后台这样返回了,那前端这边很好解决吧,也就一个foreach循环,在请求一下就行了,因为我们这个项目是vue3 + ts,且这个分类有可能被后面需要用到,那行吧,写成一分类的hooks吧,要用到时候,就import一下就行了,既然想好,那开干吧

具体业务需求实现图:

截屏2022-09-04 23.14.06.png

问题

代码用forEach写完了,一运行,哎,问题来了,怎么子级的都没有加上,可是console。log出来的又有,难道是响应式的问题,因为整个list我是用了ref来定义的,不应该哇,可是点击上面的标签切换,又正常,难道是渲染的问题,于是我给它加个nextTick,可是还是有问题,该怎么解决才能让我们代码运行正常:就是给每个标签childrens加上回对应的子级。

排查

因为list是响应式,那我打印的方式,应该是有点问题,因为我是直接console.log(list.value),因为list是响应式,所以后面它变时候,影响到了打印,导致打印的不是当时forearch里执行的结果,那我要打印时,不受响应式影响,该如何打印呢,这个问题简单,把它变成不是响应式的就行了,我执行console.log(JSON.stringify(list.value);果然一打印,就看到了,forEach执行的当时,children是空的:

截屏2022-09-04 23.27.13.png

此时到这里,我就有个疑问了,forEach里执行异步是有问题吗?结果还真是有问题,我们换原生的for循环来试试看:

截屏2022-09-04 23.29.18.png

这个就正常了,是我想要的结果

问题到了这,结果就很明显了,forEarch里执行await会并行的,并不是我认为的简单的循环,这一了解,我就去查看了一下js的几大循环的区别,具体我就不展开了,相关的链接在下面:

# 有了for循环 为什么还要forEach?

forEach源码

问题总的解决方案:

  1. 直接使用for循环解决,或者for。。。of,有些项目可能开启了eslint的no-await-in-loop这个规则的话,需要使用promise.all来解决no-await-in-loop不过此时的请求是没有顺序的,如果要有顺序的,则可以用队列的方式来实现,当然,最简单直接就是// eslint-disable-next-line no-await-in-loop,在当前行禁用这个规则;
  2. 直接与后台沟通,让他提供一个接口放回所有的,或者直接一个接口可以动态加载也行