1# 定义
nextTick 是 Vue.js 提供的一个方法,用于在下次 DOM 更新循环结束之后执行延迟回调,使用 Vue.nextTick() 或者 this.$nextTick() 都是调用 nextTick() 这个方法 。在 Vue.js 中,当你修改数据后,DOM 不会立即更新,而是等待当前事件循环完成后才进行更新。如果你想要在 DOM 更新后执行一些操作,就可以使用 nextTick() 方法。
语法:function nextTick(callback?: () => void): Promise<void>
2# $nextTick 执行流程
$nextTick 的执行流程如下:
- 调用
$nextTick方法: 当我们在 Vue 组件中调用$nextTick方法时,Vue 会将传入的回调函数添加到一个队列中。 - 等待当前任务完成: Vue 利用浏览器的异步机制来延迟执行这些回调函数,确保它们不会立即执行。
- 等待事件循环完成: 在当前事件循环中,当所有同步代码执行完成后,浏览器会处理微任务队列。
- 执行回调函数: Vue 将队列中的回调函数作为微任务添加到微任务队列中,确保在 DOM 更新后执行这些回调。
- 更新 DOM: 浏览器会继续执行微任务队列中的任务,其中包括
$nextTick方法添加的回调函数。这样可以确保在 DOM 更新后执行相应的操作。 - 清空队列: 执行完微任务队列中的回调函数后,浏览器会重新渲染页面,并将更新后的 DOM 显示给用户。
- 异步更新: 这种异步更新的机制能够确保在正确的时机处理 DOM 更新后的操作,避免阻塞主线程而提高性能。
3# nextTick 实现原理
nextTick 实现原理是利用微任务(Microtask)或宏任务(Macrotask)机制,根据优先级选择合适的异步任务调度方式(如 Promise、MutationObserver、setImmediate 或 setTimeout 等技术), 确保在当前更新循环结束后执行回调函数,从而在 DOM 更新后立即响应并获取最新状态。
callbacks:一个回调队列,用于存放异步执行的回调。pending:一个异步锁标记位,避免将timerFunc重复推送到任务队列中去。timerFunc:一个根据优先级选择合适的定时器函数,选择优先级为promise.then > MutationObserver > setImmediate > setTimeout, 无论那种timerFunc最终都会执行flushCallbacks函数。flushCallbacks: 负责执行callbacks中的回调函数,它会遍历回调函数队列并依次执行每个回调函数。
export function nextTick(cb?: Function, ctx?: Object) {
let _resolve;
// 若存在回调函数则直接放进回调队列 callbacks 中
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx);
} catch (e) {
handleError(e, ctx, 'nextTick');
}
} else if (_resolve) {
_resolve(ctx);
}
})
// 异步锁 pending 为 true 表示正在执行回调函数
if (!pending) {
pending = true;
timerFunc();
}
// 若没有提供回调函数但支持 Promise,则返回一个 Promise
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve;
})
}
}