前言
在学习vue中的nextTick的时候,发现$nextTick和Promise.then在不同情况下执行顺序不一样
一、正文
先说结论,在vue2中,当发生dom更新的时候,$nextTick回调会在下一个事件循环的微任务阶段优先执行。这意味着,在发生 DOM 更新的情况下,$nextTick会在其他微任务之前执行,比如下面这段代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 2 Example</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.7/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{ count }}</p>
<button @click="change">click +1</button>
</div>
<script>
new Vue({
el: '#app',
data: {
count:0
},
methods: {
change() {
this.count = this.count + 1
console.log("------------")
new Promise(function(resolve){
resolve()
}).then(function(){
console.log("promise")
})
this.$nextTick(() => console.log('nexttick'))
}
}
})
</script>
</body>
</html>
我在界面上创建了一个按钮,当我点击按钮的时候,会修改data中count的值,并在界面上显示,同时触发两个回调(Promise.then和$nextTick),然后输出结果是这样的:
有很多的文章已经详细说明了nextTick的源码,这里就不细说了,我们现在看到如果修改了dom,那么nextTick是先于Promise.then运行的没有问题,那么如果我不修改dom呢?
change() {
//this.count = this.count + 1
console.log("------------")
new Promise(function(resolve){
resolve()
}).then(function(){
console.log("promise")
})
this.$nextTick(() => console.log('nexttick'))
}
跟上面同样的代码,我将修改界面的count++部分注释掉,点击按钮后得出的结果:
这里由于没有发生dom更新,nextTick内部回调同样也是创建Promise,所以在没有发生dom更新的情况下,是按照代码顺序被压入微任务队列,这里Promise.then在nextTick之前,所以输出是promise,nexttick
想知道nextTick的源码可可以看这个链接
二、Vue3的情况
我同样试了vue3,vue3重写了nextTick方法,发现跟vue2的情况相反,在发生dom更新时,是先Promise.then,再nextTick。
总结
-
Vue2中,如果发生了 DOM 更新,nextTick
()
的回调会在 DOM 更新后立即执行。在 Vue 2 的源码中,每当发生 DOM 更新时,Vue 都会调用 nextTick()
函数将相关的回调函数推入队列。在下一个事件循环的微任务阶段,这些回调函数会被立即执行。 -
如果没有发生 DOM 更新,nextTick
()
的回调和 Promise 的回调会按照它们在微任务队列中的顺序执行,即它们在代码中的声明顺序。在这种情况下,nextTick()
回调和 Promise 回调都会作为微任务被添加到队列中,浏览器会按照它们在队列中的顺序执行这些回调函数。