nexttick 源码:
全局定义了一个 callbacks 数组 、 timerFunc、pending、isUsingMicroTask
接收两个参数: 回调函数 对象
1. 如果有回调函数,将回调函数包裹到一个函数中 ; 如果为空 resolve (对象); 放到callbacks 数组中
暴露一个nexttick 方法
export function nexttick(cb?:function, cxt?:object) {
let _resolve
callbacks.push(()=> {
if(cb) {
try {
cb.call(cxt)
} catch(err) {
console.log(err)
}
} else {
}
})
}
如果非空, 回调函数指向该对象cb.call(ctx); // 指向ctx 并立马执行 但是现在被包含到了一个函数里面 所以需要外部函数执行 这个才会执行 就是上面代码里面的 copies[i]()
2 . 继续执行:判断pending是否为false, 如果是false, 表示nexttick 中还未开启任务队列;判断当前是否已经开启了任务队列, 如果为true 则不再重复执行,只把回调函数加入到callbacks数组里面就好了,
设置Pending 为true ,调用timerFunc函数;
timerFunc 函数里面是一个异步函数调用,开启异步操作(微任务或者宏任务 需要等到调用栈清空之后执行) 具体见下面
3. 继续执行: 如果回调函数为空 并且支持promise, 返回一个promise 对象;
所以如果我们 console.log(this.$nexttick())返回的是一个promise 对象
timerFunc :主要是判断当前环境是否支持以下方法,使用所支持的第一种方法
if() {
支持promise promise.then
const p = new Promise()
timerFunc = p.then((flushCallbacks)
微任务
}
else if(支持 MutationObserver) {
微任务
}
else if(支持setImmediate) {
timerFunc = setImmediate(flushCallbacks)
}
else {
timerFunc = setTimeout(flushCallbacks,0)
}
然后在方法里面调用 flushCallbacks 方法
flushCallbacks:
这个方法是设置pending = fals以及开始定义的callbacks数组进行操作,对callbacks数组进行拷贝,防止原始的callbacks数组被更改造成影响;
对callbacks数组循环调用
function flushCallbacks() {
pending = false
let copies = callbacks.slice(0)
callbacks.length = 0
for(let i = 0 ; i < copies .length; I ++) {
copies[i]() // 函数执行
}
作用: vue 更新数据之类,在这里面可以立马获取到更新后的dom元素值;
vue 视图渲染是异步的 ,在同一事件循环的数据更新会放到同一个队列中,并进行去重工作,最终也是在nextTick 中的flushcallbacks执行dom 更新;
Vue 中视图更新是异步的,当data数据修改之后,视图不会立马更新,而是开启一个缓冲队列,缓冲同一事件循环的更新事件,
最后调用nextTick 方法, 把更新视图的方法 放入到callbacks 数组中,开启异步任务(根据环境判断到底执行哪种任务,微任务、宏任务)
重要的是一个字段pending 判断当前是否已经开启了任务队列, 如果为true 则不再重复执行,只把回调函数加入到callbacks数组里面就好了,
最终会在异步任务中等待一起执行,
只有当执行该异步任务的时候 ,才会再次把pending设置为false, 同时callbacks 清空。再次执行下一次任务