nextTick
是 Vue
提供的一个全局的API
,由于Vue
的异步更新策略导致我们对数据的修改不会立马体现到都没变化上,此时如果想要立即获取更新后的dom
的状态,就需要使用这个方法。
Vue
在更新dom
时是异步执行的。只要监听到数据变化,Vue
将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个watcher
被多次触发,只会被推入到队列中一次。这种在缓存时去重对于避免不必要的计算和dom
操作是非常重要的。nextTick
方法会在队列中加入一个回调函数,确保该函数在前面的dom
操作完成后才调用。
const callback = [];
let pendding = false;
function flushCallbacks(){
padding =false;
const copies = callback.slice(0)
callback.length = 0
for(let i = 0;i < copies.length;i++){
copies[i]()
}
}
let microTimeFunc;
const p = promise.resolve();
microTimeFunc = ()=>{
p.then(flushCallbacks)
}
function nextTick(cb,ctx){
if(cb){
callback.push(()=>{
cb.call(ctx)
})
}
if(!pendding){
pendding = true
microTimeFunc()
}
}
原理:
当调用nextTick
方法时会传入两个参数,回调函数和执行回调函数的上下文环境,如果没有提供回调函数,那么将返回promise
对象。首先将拿到的回调函数存放到数组中,判断是否正在执行回调函数,如果当前没有在pending
的时候,就会执行microTimeFunc
,多次执行nextTick只会执行一次microTimeFunc
,microTimeFunc
其实就是执行异步的方法,在microTimeFunc
方法中选择一个异步方法(首先判断是否支持promise
,如果支持就将flushCallbacks
放在promise
中异步执行,并且标记使用微任务。如果不支持promise
就看是否支持MutationObserver
方法,如果支持就new
了一个MutationObserver
类,创建一个文本节点进行监听,当数据发生变化了就会异步执行flushCallbacks
方法。如果以上两个都不支持就看是否支持setImmediate
方法,如果支持setImmediate
就去异步执行flushCallbacks
方法。如果以上三种方法都不支持,就使用setTimeout
),然后异步去执行flushCallbacks
方法,flushCallbacks
中就是将传递的函数依次执行。
nextTick
多次调用会维持一个数组,之后会异步的把数组中的方法以此执行,这样的话用户就会在视图更新之后再获取到真实的dom
元素。