Vue响应式更新采用“标记→收集→批量执行”流程:setter触发依赖通知,Watcher入队后异步批量更新DOM,需用nextTick()确保获取更新后的DOM。

Vue 的响应式更新不是一改就立刻重绘,而是经过一套“标记→收集→批量执行”的流程。关键在于:数据变化本身不直接操作 DOM,而是触发依赖通知,再由系统统一调度视图更新。
setter 触发依赖通知
当你修改一个响应式属性(如 obj.count = 5),实际调用的是 Vue 内部重写的 setter。这个 setter 不只是赋值,还会做两件事:
- 更新内部值,并检查新旧值是否真的不同(避免无意义触发)
- 调用该属性对应的 Dep.notify(),遍历所有订阅它的 Watcher(比如组件渲染函数、计算属性、watch 回调)
Watcher 接收通知并入队
每个 Watcher 收到通知后,并不会马上重新渲染。它会把自己标记为“待更新”,然后被推入一个全局异步更新队列:
- 同一轮事件循环中多次修改同一个或多个响应式数据,只会触发一次队列刷新
- 队列在当前同步代码执行完后,以 microtask(如 Promise.then)方式清空,保证高效且不阻塞主线程
- 这也是为什么连续执行 count++ 三次,组件只重新渲染一次
更新执行与 DOM 同步
队列清空时,所有待更新的 Watcher 按顺序执行:
立即学习“前端免费学习笔记(深入)”;
- 先重新运行渲染函数,生成新的虚拟 DOM 树
- 与旧树进行 Diff 比对,找出最小变更集
- 将差异映射为真实 DOM 操作(增删改节点、更新属性、文本等)
- 整个过程批量完成,减少浏览器重排重绘次数
如何确保拿到更新后的 DOM
因为更新是异步的,直接在赋值后查询 DOM 元素尺寸或 focus 状态往往得不到预期结果。必须使用:
- nextTick():把回调推入 microtask 队列,确保在本次 DOM 更新完成后执行
- 不要用 setTimeout 替代,它属于 macrotask,时机不可控,可能夹杂其他渲染或用户交互
- 在 Composition API 中,await nextTick() 可用于 await 等待更新完成


















