简单理解Vue中的nextTick
Vue 中的 nextTick 涉及到 Vue 中 DOM 的异步更新
为什么需要 nextTick
Vue 是异步修改 DOM 的并且不鼓励开发者直接接触 DOM,但有时候业务需要必须 对数据更改–刷新后的 DOM 做相应的处理,这时候就可以使用 Vue.nextTick(callback)
这个 api 了
理解原理前的准备
首先需要知道事件循环中宏任务和微任务这两个概念
详细介绍指路 javascript 执行机制
常见的宏任务有:script,setTimeout,setInterval,setImmediate,I/O,UI rendering
常见的微任务有:process.nextTick(nodejs),Promise.then(),MutationObserver
理解 nextTick 的原理
正是 vue 通过异步队列控制 DOM 更新和 nextTick 回调函数先后执行的方式。如果大家看过这部分的源码,会发现其中做了很多 isNative()的判断,因为这里还存在兼容性优雅降级的问题
示例
先来一个示例了解下关于 Vue 中的 DOM 更新以及 nextTick 的作用。
模板
1 | <div class="app"> |
Vue 实例
1 | new Vue({ |
点击前
点击后
从图中可以得知:msg1 和 msg3 显示的内容还是变换之前的,而 msg2 显示的内容是变换之后的。其根本原因是因为 Vue 中 DOM 更新是异步的
异步更新队列
Vue 在内部对异步队列尝试使用原生的Promise.then
、MutationObserver
和setImmediate
,如果执行环境不支持,则会采用 setTimeout(fn, 0)
代替。
Promise.then 的延迟调用
1 | if (typeof Promise !== "undefined" && isNative(Promise)) { |
如果浏览器支持 Promise,那么就用 Promise.then 的方式来延迟函数调用,Promise.then 方法可以将函数延迟到当前函数调用栈最末端,也就是函数调用栈最后调用该函数。从而做到延迟。
MutationObserver
1 | else if ( |
MutationObserver 是 h5 新加的一个功能,其功能是监听 dom 节点的变动,在所有 dom 变动完成后,执行回调函数。
具体有一下几点变动的监听:
- childList:子元素的变动
- attributes:属性的变动
- characterData:节点内容或节点文本的变动
- subtree:所有下属节点(包括子节点和子节点的子节点)的变动
可以看出,以上代码是创建了一个文本节点,来改变文本节点的内容来触发的变动,因为我们在数据模型更新后,将会引起 dom 节点重新渲染,所以,我们加了这样一个变动监听,用一个文本节点的变动触发监听,等所有 dom 渲染完后,执行函数,达到我们延迟的效果。
setTimeOut 延迟器
1 | else { |
利用 setTimeout 的延迟原理,setTimeout(func, 0)会将 func 函数延迟到下一次函数调用栈的开始,也就是当前函数执行完毕后再执行该函数,因此完成了延迟功能。