vue响应式数据变更后dom批量更新:setter触发通知但不立即更新,变更被去重后推入微任务队列,待同步代码执行完再统一排序、刷新,确保高效稳定。

Vue 响应式数据变更后,DOM 更新不是逐次执行,而是统一收集、去重、排序后再一次性刷新——这就是批处理的核心。
变更触发:setter 通知,但不立即更新
当你修改 ref 或 reactive 数据时,对应的 setter 被触发,内部会调用 Dep.notify(),通知所有依赖该数据的 Watcher “我变了”。但此时 DOM 完全不动,每个 Watcher 的 update() 方法只是把自身推入一个异步队列,而不是立刻执行渲染。
队列管理:去重 + 单次注册 + 微任务调度
Vue 的调度器(scheduler)确保同一轮事件循环中:
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 相同组件的多个变更只进队列一次(靠 Watcher.id 去重)
- 无论你连续赋值三次还是十次,最终只保留最后一次状态
- 只要队列尚未开始清空,就只调用一次 nextTick(flushSchedulerQueue)
- 这个 nextTick 默认使用 MutationObserver(微任务),不支持时降级为 Promise.then 或 setTimeout
批量刷新:按序执行,一次完成真实 DOM 更新
等到当前同步代码全部执行完、微任务队列开始执行时,flushSchedulerQueue 被调用:
- 先对队列中的 Watcher 按 id 升序排序(保证父组件优先于子组件更新)
- 再遍历执行每个 Watcher 的 run() 方法
- run() 内部触发 component.render() → 生成新 vnode → patch() 对比并更新真实 DOM
- 整个过程在单次微任务中完成,浏览器不会在此期间重绘
为什么必须批处理?
直接同步更新 DOM 会导致严重性能问题:
- 频繁 reflow / repaint(比如连续改 5 个 class,触发 5 次布局计算)
- 视图状态不一致(中间态可能被用户看到)
- 父子组件更新顺序错乱(子先于父更新,可能读到旧 props)
批处理让 Vue 在“改完再刷”和“刷得又快又稳”之间取得关键平衡。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










