Vue的虚拟DOM补丁(patch)本身同步执行,但整个更新流程由微任务异步调度,实现批量更新与视图最终一致性;同一事件循环内多次数据变更仅触发一次patch,$nextTick确保在patch完成后执行回调。

Vue.js 的虚拟 DOM 补丁更新(patch)本身是同步执行的,但整个更新流程被包裹在异步微任务中调度,这是响应式更新“批量更新”和“视图最终一致性”的关键设计。
响应式触发后,更新被推入微任务队列
当响应式数据变化(如 setter 触发依赖通知)时,Vue 会为关联的 watcher 标记为“待更新”,但不会立即执行 render 和 patch。而是调用 queueWatcher,将 watcher 推入一个全局队列,并确保在当前 tick 结束前,仅以 Promise.then、MutationObserver 或 setImmediate(降级)的方式,在下一个微任务中统一 flush 队列。
- 同一事件循环内多次数据修改,只会触发一次 patch
- 这避免了重复渲染和中间无效 DOM 状态
- 开发者调用 this.message = 'a'; this.message = 'b';,最终只渲染 'b'
patch 过程本身是同步的,但时机由微任务控制
真正执行 virtual DOM diff 和 DOM 操作补丁(patchVNode / patchElement) 是同步函数调用,没有内部异步逻辑。它的“异步感”完全来自执行时机:它总是在微任务回调中被调用,因此一定晚于同步代码,早于宏任务(如 setTimeout)。
- vm.$nextTick() 就是显式地往同一个微任务队列追加回调,确保在 patch 完成后执行
- 直接操作 DOM(如 ref.value.innerHTML)在 nextTick 回调里才安全,因为此时新 DOM 已就位
- 若在同步代码中立即读取 offsetHeight,可能拿到旧值;需等微任务后
微任务调度器的兼容性与优先级选择
Vue 2/3 均优先使用 Promise.then(最可靠微任务),其次尝试 MutationObserver(用于监听 DOM 变化,也可伪造微任务),最后降级到 setImmediate(IE)或 setTimeout(fn, 0)(极低优先级兜底)。这种分层策略保证了跨浏览器下更新时机的一致性。
Vue 3 组合式 API 与 最佳实践,涵盖代码组织、useXxx 模式、组合式函数设计、Store 集成、响应式优化及功能抽取。
立即学习“前端免费学习笔记(深入)”;
- Promise 方案确保所有 watcher flush 在同一轮微任务中,顺序稳定
- MutationObserver 在某些老版 iOS Safari 中比 Promise 更早触发,Vue 会做对齐处理
- 不依赖 requestIdleCallback 或宏任务,因其无法满足“及时且批量”的要求
开发中需注意的典型场景
理解微任务调度有助于写出更可预测的代码:
- 在 v-for 中修改数组并期望 ref 列表立刻可用?要 nextTick
- 使用 watch 监听响应式对象,赋值后立即读取 DOM?同样需要 nextTick
- 服务端渲染(SSR)无微任务环境,nextTick 退化为 Promise.resolve().then,仍保持语义一致
不复杂但容易忽略:Vue 的“异步更新”不是 patch 异步,而是“何时开始 patch”被微任务精确控制。掌握这点,就能准确预判 DOM 更新节奏,避开绝大多数视图不同步问题。

















