vue nexttick 实现
Vue 中 nextTick 的实现原理
Vue 的 nextTick 用于在 DOM 更新后执行回调函数,确保操作基于最新的 DOM 状态。其核心实现依赖于 JavaScript 的事件循环机制。
核心机制
Vue 通过微任务(Microtask)或宏任务(Macrotask)调度回调函数。现代浏览器优先使用微任务(如 Promise、MutationObserver),降级方案为宏任务(如 setTimeout)。
源码关键实现
-
回调队列管理
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]() } } -
异步调度策略
根据环境支持情况选择最优的异步 API:- 优先使用
Promise.then(微任务) - 不支持则降级到
MutationObserver或setImmediate - 最终使用
setTimeout(宏任务)
let timerFunc if (typeof Promise !== 'undefined') { const p = Promise.resolve() timerFunc = () => { p.then(flushCallbacks) } } else if (typeof MutationObserver !== 'undefined') { // 降级到 MutationObserver } else { timerFunc = () => { setTimeout(flushCallbacks, 0) } } - 优先使用
-
nextTick 函数
将回调推入队列并触发异步执行:function nextTick(cb, ctx) { callbacks.push(() => { if (cb) cb.call(ctx) }) if (!pending) { pending = true timerFunc() } }
使用场景示例
-
DOM 更新后操作
在数据变化后立即操作 DOM 需通过nextTick确保 DOM 已更新:this.message = 'updated' this.$nextTick(() => { console.log(document.getElementById('text').innerHTML) // 获取最新 DOM }) -
异步组件加载
动态加载组件后通过nextTick访问组件实例:components: { AsyncComp: () => import('./AsyncComp.vue') }, mounted() { this.$nextTick(() => { console.log(this.$refs.asyncComp) // 组件实例已挂载 }) }
注意事项
-
微任务与宏任务差异
微任务会在当前事件循环的末尾执行,而宏任务在下一次事件循环开始执行。Vue 优先使用微任务以保证更快的响应速度。 -
兼容性处理
源码中对不同环境的降级策略确保了在旧浏览器(如 IE9)中仍能正常工作。
通过这种设计,nextTick 成为 Vue 响应式系统中协调 DOM 更新与异步操作的关键工具。







