Vue2 nextTick
核心源码位置
Vue 2 的 nextTick
实现主要在 src/core/util/next-tick.js
文件中。
完整源码结构
import { noop } from 'shared/util'
import { handleError } from './error'
import { isIE, isIOS, isNative } from './env'export let isUsingMicroTask = falseconst callbacks = []
let pending = falsefunction flushCallbacks () {pending = falseconst copies = callbacks.slice(0)callbacks.length = 0for (let i = 0; i < copies.length; i++) {copies[i]()}
}let timerFuncif (typeof Promise !== 'undefined' && isNative(Promise)) {const p = Promise.resolve()timerFunc = () => {p.then(flushCallbacks)if (isIOS) setTimeout(noop)}isUsingMicroTask = true
} else if (!isIE && typeof MutationObserver !== 'undefined' && (isNative(MutationObserver) ||MutationObserver.toString() === '[object MutationObserverConstructor]'
)) {let counter = 1const observer = new MutationObserver(flushCallbacks)const textNode = document.createTextNode(String(counter))observer.observe(textNode, {characterData: true})timerFunc = () => {counter = (counter + 1) % 2textNode.data = String(counter)}isUsingMicroTask = true
} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {timerFunc = () => {setImmediate(flushCallbacks)}
} else {timerFunc = () => {setTimeout(flushCallbacks, 0)}
}export function nextTick (cb?: Function, ctx?: Object) {let _resolvecallbacks.push(() => {if (cb) {try {cb.call(ctx)} catch (e) {handleError(e, ctx, 'nextTick')}} else if (_resolve) {_resolve(ctx)}})if (!pending) {pending = truetimerFunc()}if (!cb && typeof Promise !== 'undefined') {return new Promise(resolve => {_resolve = resolve})}
}
关键点解析
1. 回调队列管理
-
callbacks
: 存储所有待执行的回调函数 -
pending
: 标记是否已经有回调队列正在等待执行 -
flushCallbacks
: 执行所有回调并清空队列
2. 异步执行策略 (timerFunc)
Vue 2 采用了降级策略来选择最佳的异步执行方式,优先级如下:
(1) 首选 Promise (微任务)
(2) 次选 MutationObserver (微任务)
(3) 再次选 setImmediate (宏任务)
(4) 最后选择 setTimeout (宏任务)
3. nextTick 函数实现
-
支持两种调用方式:
-
回调函数形式:
nextTick(callback)
-
Promise 形式:
nextTick().then(...)
-
-
错误处理:捕获回调执行中的错误并通过 Vue 的错误处理系统处理
与 Vue 3 的主要区别
-
兼容性处理:Vue 2 有复杂的降级策略,Vue 3 只使用 Promise
-
微任务控制:Vue 2 明确标记
isUsingMicroTask
来跟踪是否使用微任务 -
实现复杂度:Vue 2 需要处理更多边界情况和浏览器怪癖
-
Promise 返回:Vue 2 需要额外处理 Promise 返回的逻辑
设计思想
-
批量更新:通过回调队列实现多个更新的批量处理
-
异步更新:确保 DOM 更新是异步执行的,提高性能
-
执行时机:尽可能使用微任务以更早执行回调
-
兼容性:在各种环境中都能正常工作
Vue 2 的 nextTick
实现展示了框架如何在不同浏览器环境中提供一致的异步行为,同时也体现了对性能的极致追求。