vue nexttick 实现
Vue nextTick 的实现原理
Vue 的 nextTick 方法用于在下次 DOM 更新循环结束之后执行延迟回调。其核心实现基于 JavaScript 的事件循环机制,结合微任务(microtask)和宏任务(macrotask)的调度策略。
核心实现机制
Vue 内部维护一个回调队列(callbacks),并通过异步方式依次执行这些回调。nextTick 会将传入的回调函数推入队列,并确保在适当的时机触发队列的执行。
let callbacks = [];
let pending = false;
function flushCallbacks() {
pending = false;
const copies = callbacks.slice(0);
callbacks.length = 0;
for (let i = 0; i < copies.length; i++) {
copies[i]();
}
}
异步调度策略
Vue 会根据当前环境选择最优的异步调度方式,优先级如下:
- Promise(微任务):优先使用原生
Promise.then。 - MutationObserver(微任务):作为 Promise 的降级方案。
- setImmediate(宏任务):Node.js 环境专用。
- setTimeout(宏任务):最终降级方案。
let timerFunc;
if (typeof Promise !== 'undefined') {
const p = Promise.resolve();
timerFunc = () => {
p.then(flushCallbacks);
};
} else if (typeof MutationObserver !== 'undefined') {
// 降级为 MutationObserver
} else if (typeof setImmediate !== 'undefined') {
timerFunc = () => {
setImmediate(flushCallbacks);
};
} else {
timerFunc = () => {
setTimeout(flushCallbacks, 0);
};
}
nextTick 函数实现
nextTick 的主要逻辑是将回调推入队列,并触发异步执行:
function nextTick(cb, ctx) {
let _resolve;
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx);
} catch (e) {
handleError(e, ctx, 'nextTick');
}
} else if (_resolve) {
_resolve(ctx);
}
});
if (!pending) {
pending = true;
timerFunc();
}
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve;
});
}
}
使用场景示例
-
DOM 更新后操作:
this.message = 'updated'; this.$nextTick(() => { console.log('DOM updated:', this.$el.textContent); }); -
结合 Promise 使用:
this.$nextTick().then(() => { console.log('DOM updated'); });
注意事项
- 微任务与宏任务的区别:微任务(如 Promise)会在当前事件循环末尾执行,而宏任务(如 setTimeout)会进入下一个事件循环。Vue 优先使用微任务以保证更快的响应。
- 兼容性处理:
nextTick会自动降级到兼容性更好的方案,确保在不同环境中正常运行。 - 错误处理:回调中的错误会被 Vue 捕获并统一处理,避免影响主流程。







