$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中,通过这个异步方法清空当前队列。