Vue的数据更新是异步批量处理:数据变更触发Watcher入队去重,nextTick以微任务调度flushSchedulerQueue执行DOM更新,回调在DOM更新后、浏览器渲染前执行。

Vue 的数据更新不是“改完立刻渲染”,而是走一套有缓冲、可合并、带时机控制的流程。理解这个序列,才能真正用好 nextTick,而不是把它当成“等 DOM 变了就执行”的黑盒。
数据变更触发 Watcher 入队
当你修改响应式数据(比如 this.count = 5),setter 被触发,对应 Watcher 的 update() 方法被调用。此时 Vue 并不立即渲染,而是执行 queueWatcher:
- 用哈希表
has[id]去重:同一 Watcher 多次触发只入队一次 - 若队列尚未刷新(
!flushing),直接推入queue数组 - 若正在刷新(
flushing === true),则按id插入合适位置,保证顺序 - 只要队列非空且未启动刷新,就调用
nextTick(flushSchedulerQueue)调度刷新
nextTick 调度本质是微任务排队
nextTick 不是定时器,而是一套渐进式微任务封装:
- 优先使用
Promise.then(现代环境)—— 最快、最标准的微任务 - 降级为
MutationObserver(监听 DOM 变化)—— 兼容性好,仍属微任务 - 最后 fallback 到
setTimeout(fn, 0)—— 实际是宏任务,但作为兜底保障可用
无论哪种方式,目标都是把 flushSchedulerQueue 推入微任务队列,在当前同步代码结束后、浏览器渲染前执行。
使用 `@ainative/vue-sdk` 为 Vue 3 应用添加 AI 聊天功能。适用于以下场景:(1) 安装 `@ainative/vue-sdk`,(2) 在 Vue 组件中使用 `useChat` 组合式函数,(3) 提供……
立即学习“前端免费学习笔记(深入)”;
DOM 更新发生在 flushSchedulerQueue 中
当微任务执行时,Vue 开始批量处理队列:
- 对
queue中所有 Watcher 按id排序(避免子组件先于父组件更新) - 逐个调用
watcher.run()→ 触发render→ 生成新 VNode →patch差异更新真实 DOM - 注意:此时 DOM 树结构已更新,但浏览器尚未重绘(页面还没“看起来变了”)
nextTick 回调在 DOM 更新后、渲染前执行
你传给 this.$nextTick(() => {...}) 的回调,会被 Vue 放进同一个微任务队列,排在 flushSchedulerQueue 之后:
- 同步代码结束
- → 微任务1:
flushSchedulerQueue(完成 DOM 结构更新) - → 微任务2:
你的回调(可安全读取更新后的 DOM 节点、offsetHeight、getBoundingClientRect 等) - → 浏览器才进行 Layout & Paint(用户真正看到变化)
所以 nextTick 保证的是“DOM 已按最新数据更新完毕”,不是“页面已显示出来”。这是它和 setTimeout(..., 0) 的关键区别。

















