vue响应式核心是dep与watcher通过订阅-发布模式协同:dep用subs数组收集依赖的watcher,watcher在数据变更时异步批量更新;dep.target临时绑定实现依赖收集,vue3改用proxy与activeeffect栈替代。

Vue.js 的响应式核心依赖于 Dep(依赖收集器)和 Watcher(观察者)之间的协同工作:Dep 负责记录哪些 Watcher 依赖于某个响应式数据,Watcher 则在数据变化时被通知并执行更新逻辑。二者通过“订阅-发布”模式通信,不直接持有对方引用,而是借助闭包与全局状态(如 Dep.target)临时建立关联。
Dep 如何收集依赖
每个响应式属性(或 reactive 对象的 key)对应一个独立的 Dep 实例。当组件 render 函数首次执行时,会触发属性的 getter,此时:
- 若存在全局的
Dep.target(即当前正在求值的 Watcher),Dep 将其添加到自己的subs数组中; - Watcher 通过
addDep()方法主动向对应 Dep 实例订阅自己; - Dep 内部使用 Set 去重,避免同一 Watcher 被重复添加。
Watcher 如何触发更新
当响应式数据被修改(触发 setter)时,对应 Dep 实例调用 notify() 方法:
分析 Vue 3 Composition API 使用情况——审计响应式模式、可组合函数设计、ref 与 reactive 的选择、计算属性、watcher 使用及组件……
- 遍历
subs中所有 Watcher,依次调用其update()方法; -
update()默认采用异步队列机制(queueWatcher),合并重复更新、去重,并在 nextTick 后批量执行run(); -
run()重新求值(如重新执行 render 函数),并触发视图更新或用户定义的watch回调。
Dep.target 是如何临时绑定的
Dep.target 是一个单例变量,仅在 Watcher 构造和求值阶段被设置:
- 创建 Watcher 实例时,会先将自身赋给
Dep.target,再立即执行传入的getter(如 render 函数); - 在 getter 执行过程中,访问的响应式属性 getter 内部读取
Dep.target并完成依赖收集; - getter 执行完毕后,立即清空
Dep.target = null,防止污染后续依赖收集。
Vue 2 与 Vue 3 的关键差异
Vue 2 使用 Object.defineProperty + Dep/Watcher 手动管理依赖;Vue 3 改用 Proxy + effect + track/trigger 机制,但思想一脉相承:
- Vue 2 的 Dep 相当于 Vue 3 中的依赖“桶”(由
targetMap管理); - Vue 2 的 Watcher 对应 Vue 3 中的 effect 函数,
effect(fn)自动完成依赖追踪; - Vue 3 不再有全局
Dep.target,而是通过栈(activeEffect)实现嵌套 effect 的正确追踪。
理解 Dep 与 Watcher 的协作方式,是掌握 Vue 响应式原理的关键入口。它不复杂,但容易忽略其中的时机控制与临时状态设计。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










