017 $nextTick()使用以及原理

125 阅读2分钟

$nextTick()使用以及原理

使用:它可以在DOM更新完毕之后执行一个回调;

原理:浏览器机制宏任务微任务

宏任务(Macrotask):

setTimeout, setInterval, script(整体代码块),MessageChannel, I/O, 事件队列

微任务(Microtask):

MutationObserver(浏览器环境),Promise.[then/catch/finally], process.nextTick(Node环境)

1. $nextTick()有什么用?

Vue是异步渲染的框架。

data改变之后,DOM不会立刻渲染,因为dom更新是异步方法中执行的nextTick。

连续多次的异步渲染,$nextTick()只会执行最后一次渲染后的结果。

2. $nextTick的原理

代码执行步骤:

// data数据更新 => 生成新的虚拟dom => diff算法比较新旧虚拟dom => patch更新变化的虚拟dom到真实的dom上 => 触发更新回调
<div class="submit-btn" ref="btn" @click="submit">
    下一步{{ time }}
</div>
<script>
	submit() {
        this.time = Math.random()*10
    	console.log(this.$refs.btn)
    	console.log(this.$refs.btn.innerText)
    	this.$nextTick(() => {
            console.log("dom更新了的1")
        })
    	this.$nextTick(() => {
            console.log("dom更新了的2")
        })
    }
</script>

this.time = Math.random()*10, 数据改变时, 调用了watcher观察者中的update,update方法通过调用nextTick方法,把更新dom的方法加入到异步任务队列中。

自己页面上用的this.nextTick方法,也会把回调方法加入到异步队列中。如果自己的页面多次调用this.nextTick方法,也会加入到异步队列中。

加入到队列中的异步方法,会依次执行:DOM更新的回调--自己页面的this.$nextTick()回调函数。

中间涉及到根据浏览器的环境去判断,这些回调方法,加入哪个异步方法中去执行?

nextTick 并不是浏览器本身提供的一个异步API,而是Vue中,用浏览器本身提供的原生异步API封装而成的一个异步封装方法。

它对于浏览器异步API的选用规则如下:

Promise存在,取Promise.then; 不存在Promise则取MutationObserver; MutationObserver不存在则取setImmediate; setImmediate不存在则最后取setTimeout来实现。

nextTick即有可能是微任务,也有可能是宏任务,从优先取Promise和MutationOserver 可以看出nextTick优先微任务,其次是setImmediate和setTimeout宏任务。

同步代码执行完毕后,优先执行微任务,其次才会执行宏任务。

3. 循环调用的话nextTick里面有容错机制吗?

多次调用nextTick 会将方法存入队列callbacks中,通过这个异步方法清空当前队列。