我是靠谱客的博主 无辜皮带,这篇文章主要介绍Vue 异步事件更新 & 异步Dom更新解决方案,现在分享给大家,希望可以做个参考。

Vue 异步事更新件 & 异步Dom更新解决方案

    • Vue 异步事更新件 异步Dom更新解决方案
      • Question
      • Action
        • 1 正确姿势
        • 2 一个试验
        • 3 还有困惑

1. Question

这里写图片描述

最近遇到一个有点别扭的需求。

进入一个子页面,需要四个接口拿到四份数据【a,b,c,d】
其中a,b正巧父级拿到过,在父级页面上用v-if指令保证ab存在,再去展示子页面。

现在,cd必须在子页面拿到了。c依赖浏览器的query pidd依赖c的一个字段c.pgid

画一个图,大概是这样的需求:
这里写图片描述

然后我的旧实现思路是这样的:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// using typescript private created() { // 请求c后立刻请求d this.fetchC().then(this.fetchD); } // 后台请求c private fetchC() { this.$store.dispatch('resource/c', this.pid); } // 从store获取c private get c() { return this.$store.getters['resource/c'](this.pid); } private get pid(): number { return Number(this.$route.query.pid); } private get pgid() { if (!this.c) { return null; } return this.c.pgid; } // 后台请求d private fetchD() { if (!this.pgid) { return; } return this.$store.dispatch('resource/d', this.pgid); } // store拿d private get d() { return this.$store.getters['resource/d'](this.pgid); }

dispacth c之后立即then一下dispatch d。这个时候,get c()并不能保证一定已经get到,this.pgid更不一定能拿到,dispatch d方法就会报错。

这里写图片描述

当时有点蒙圈,其实很简单一个事,只要保证this.pgid存在的时候再去dispatch d就可以了。

2. Action

2.1 正确姿势

稍微改一点点代码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// using typescript private created() { // 请求c后不去立刻请求d了 this.fetchC(); // 此行改了 } // 后台请求c private fetchC() { this.$store.dispatch('resource/c', this.pid); } // 从store获取c private get c() { return this.$store.getters['resource/c'](this.pid); } private get pid(): number { return Number(this.$route.query.pid); } private get pgid() { if (!this.c) { return null; } return this.c.pgid; } // 后台请求d,通过监听pgid的值,存在之后再去fetchD @Watch('pgid') // 此行改了 private fetchD() { if (!this.pgid) { return; } return this.$store.dispatch('resource/d', this.pgid); } // store拿d private get d() { if (!this.pgid) { return; } // 此行改了 return this.$store.getters['resource/d'](this.pgid); }

跑起来,一切都很完美。两个接口的数据都拿到了。

这是一个思路,把重心放在数据有没有拿到上,用watch监听,等数据拿到之后,再去发送第二个请求。

这里写图片描述

但是有点慌啊,这一块感觉还是有点迷啊。

我如果不把思路放在数据上,我就去控制请求(感觉这样子更符合开发的思路,代码更容易理解),有没有哪个生命周期的时刻,第一个请求回来,get的第一个数据也成功拿到,在这个生命周期时刻,第二个请求才开始呢?

第二个请求放在$nextTick里面行不行?
不论dispatch方法的快慢问题,到底getdispatch谁先执行?有没有一个先后顺序的?

这里写图片描述

2.2 一个试验

settimeout当作dispatch测试一下。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<html> <head> <title>test</title> </head> <body> <div id="app"> <span>{{c}}</span> <span>{{d}}</span> </div> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script> var app = new Vue({ el: '#app', data: { pgid : 1 }, computed: { c: function () { if (!this.pgid) { return ; } console.log('c computed ' + this.pgid); return ++this.pgid; }, d: function () { if (!this.c) { return ; } console.log('d computed ' + this.c); return ++this.c; } }, created: function () { // 模拟c的请求,这里我不知道这个请求返回需要多少秒,假设1s setTimeout(() => { console.log('time out'); this.pgid = 100; }, 1000); this.$nextTick(() => { console.log('next tick'); this.pgid = 10; }) console.log('created'); }, mounted: function () { console.log('mounted'); } }); </script> </body> </html>

运行结果:

这里写图片描述

有图有真相了,看图学习:

官方对$nextTick的解释是:

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

官方对created方法的解释是:

在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。

官方对mounted方法的解释是:

el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。如果 root 实例挂载了一个文档内元素,当 mounted 被调用时 vm.$el 也在文档内。

注意 mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick 替换掉 mounted:

复制代码
1
2
3
4
5
6
mounted: function () { this.$nextTick(function () { // Code that will run only after the // entire view has been rendered }) }

哦,也就是说在vue的created方法结束之后,mounted方法开始,紧接着执行$nextTick这个方法。

呸,我不信!
这里写图片描述

我把延迟改成0,我的请求巨快!

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
created: function () { // 我把这个改成0 setTimeout(() => { this.pgid = 100; console.log('time out'); }, 0); this.$nextTick(() => { console.log('next tick'); this.pgid = 10; }) console.log('created'); }

结果:

这里写图片描述

好吧,并没有什么变化,还是$nextTick快。

现在,起码明白了一个事: 遇到异步事件,你用拦截异步事件的思路是不通的,mountednextTick都拦不住,用settimeout延时你又不知道异步事件的延迟具体是多少秒。实际上异步事件执行的时间更靠后。而且远远晚于dom创建和首次展示的时间。

所以两个请求在created方法时就前后发出,第二个请求又依赖第一个请求的参数,这样的姿势肯定是不正确了。

2.3 还有困惑

get一定是在created方法之后?

并不是。。。。

这里写图片描述

getdispatch方法谁先执行???比如这个get dfetch d 都依赖pgidpgid一变,谁先变??也不一定。。。。

老老实实的用数据控制一切吧。

这里写图片描述

参考:
https://juejin.im/post/5a6fdb846fb9a01cc0268618

最后

以上就是无辜皮带最近收集整理的关于Vue 异步事件更新 & 异步Dom更新解决方案的全部内容,更多相关Vue内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(64)

评论列表共有 0 条评论

立即
投稿
返回
顶部