我正在参加「掘金·启航计划」
背景
前几天在项目中有遇到一种情况,就是后台返回的一个树形结构的分类数的数据给到前端我这边,不过有需要调两个接口,一个接口是获取标签的tab,可以看成是一级的分类,一个接口就是用来获取所有的子集,因为业务所致,所以后台这样返回了,那前端这边很好解决吧,也就一个foreach循环,在请求一下就行了,因为我们这个项目是vue3 + ts,且这个分类有可能被后面需要用到,那行吧,写成一分类的hooks吧,要用到时候,就import一下就行了,既然想好,那开干吧
具体业务需求实现图:
问题
代码用forEach写完了,一运行,哎,问题来了,怎么子级的都没有加上,可是console。log出来的又有,难道是响应式的问题,因为整个list我是用了ref来定义的,不应该哇,可是点击上面的标签切换,又正常,难道是渲染的问题,于是我给它加个nextTick,可是还是有问题,该怎么解决才能让我们代码运行正常:就是给每个标签childrens加上回对应的子级。
排查
因为list是响应式,那我打印的方式,应该是有点问题,因为我是直接console.log(list.value),因为list是响应式,所以后面它变时候,影响到了打印,导致打印的不是当时forearch里执行的结果,那我要打印时,不受响应式影响,该如何打印呢,这个问题简单,把它变成不是响应式的就行了,我执行console.log(JSON.stringify(list.value);果然一打印,就看到了,forEach执行的当时,children是空的:
此时到这里,我就有个疑问了,forEach里执行异步是有问题吗?结果还真是有问题,我们换原生的for循环来试试看:
这个就正常了,是我想要的结果
问题到了这,结果就很明显了,forEarch里执行await会并行的,并不是我认为的简单的循环,这一了解,我就去查看了一下js的几大循环的区别,具体我就不展开了,相关的链接在下面:
问题总的解决方案:
- 直接使用for循环解决,或者for。。。of,有些项目可能开启了eslint的no-await-in-loop这个规则的话,需要使用promise.all来解决no-await-in-loop不过此时的请求是没有顺序的,如果要有顺序的,则可以用队列的方式来实现,当然,最简单直接就是// eslint-disable-next-line no-await-in-loop,在当前行禁用这个规则;
- 直接与后台沟通,让他提供一个接口放回所有的,或者直接一个接口可以动态加载也行