🎯 核心架构概览
整体数据流向图
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 用户访问数据 │───▶│ Proxy拦截 │───▶│ 依赖收集(track) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Dep容器创建 │◀───│ 创建Link链接 │◀───│ Subscriber记录 │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 用户修改数据 │───▶│ Proxy拦截 │───▶│ 触发更新(trigger)│
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 版本号递增 │───▶│ 通知订阅者 │───▶│ 批处理执行 │
└─────────────────┘ └─────────────────┘ └─────────────────┘
🧩 核心组件可视化
1. 双向链表结构
Subscriber (Effect/Computed) 链表结构:
头部 [Link1] ⇄ [Link2] ⇄ [Link3] ⇄ ... ⇄ [LinkN] 尾部
↑ ↑
deps指针 depsTail指针
每个Link同时存在于两个链表中:
Subscriber deps链表: Effect → Link1 → Link2 → Link3
↖_______↗
Dep subs链表: Dep → Link2 → Link1 → Link3
↖________↗
2. 依赖追踪过程
访问属性时的依赖收集流程:
step 1: activeSub = currentEffect
step 2: Proxy.get() 拦截
step 3: track(target, key)
↓
step 4: targetMap.get(target) 获取 depsMap
↓
step 5: depsMap.get(key) 获取 dep
↓
step 6: dep.track() 创建/复用 Link
↓
step 7: 建立双向链接关系
Effect.deps ⇄ Link ⇄ Dep.subs
3. 更新触发过程
修改属性时的更新流程:
step 1: Proxy.set() 拦截
step 2: trigger(target, key)
↓
step 3: depsMap.get(key) 获取 dep
↓
step 4: dep.version++ (版本递增)
step 5: dep.notify() 通知所有订阅者
↓
step 6: 批处理调度
for each subscriber in dep.subs:
subscriber.notify() → 加入批处理队列
↓
step 7: endBatch() 执行所有副作用
📊 核心API工作原理图示
reactive() 工作流程
reactive(obj) 创建过程:
输入对象 obj
↓
检查是否已存在代理 ←─────────────────┐
↓ 否 │
获取对象类型 [COMMON/COLLECTION] │
↓ │
选择对应处理器 │
↓ │
new Proxy(obj, handlers) │
↓ │
proxyMap.set(obj, proxy) ──────────┘
↓
返回 proxy 对象
ref() 内部结构
ref(value) 结构示意图:
┌─────────────────────────────┐
│ RefImpl 实例 │
├─────────────────────────────┤
│ _value: T │ ◀─ 处理后的值
│ _rawValue: T │ ◀─ 原始值
│ dep: Dep │ ◀─ 独立的依赖容器
│ [IS_REF]: true │
│ [IS_SHALLOW]: boolean │
├─────────────────────────────┤
│ get value() { │
│ this.dep.track() │ ◀─ 依赖收集
│ return this._value │
│ } │
│ set value(newVal) { │
│
│ this.dep.trigger() │ ◀─ 触发更新
│ } │
└─────────────────────────────┘
computed() 执行机制
computed(getter) 工作流程:
┌─────────────────────────────────────┐
│ ComputedRefImpl │
├─────────────────────────────────────┤
│ _value: any │
│ dep: Dep (自身依赖) │
│ deps: Link (依赖的其他响应式数据) │
│ flags: DIRTY/TRACKING/EVALUATED │
└─────────────────────────────────────┘
│
get value() 时
↓
┌─────────────────────────────────────┐
│ 1. this.dep.track() │ ◀─ 收集对computed的依赖
│ 2. refreshComputed(this) │ ◀─ 刷新计算值
│ 3. return this._value │
└─────────────────────────────────────┘
│
refreshComputed() 流程
↓
┌─────────────────────────────────────┐
│ 检查flags和globalVersion快速路径 │
│ ↓ │
│ 准备依赖追踪 prepareDeps() │
│ ↓ │
│ 执行getter函数 │
│ ↓ │
│ 比较新旧值,必要时更新 _value │
│ ↓ │
│ 清理未使用依赖 cleanupDeps() │
└─────────────────────────────────────┘
🔧 副作用管理可视化
Effect执行生命周期
ReactiveEffect.run() 完整流程:
开始执行
↓
设置 RUNNING 状态
↓
cleanupEffect() ──┐
↓ │ 清理上轮副作用
prepareDeps() ◄───┘
↓
切换上下文: activeSub = this
↓
执行用户函数 fn() ──┐
↓ │ 此时进行依赖收集
cleanupDeps() ◄────┘
↓
恢复上下文
↓
清除 RUNNING 状态
↓
完成执行
依赖清理机制
cleanupDeps() 工作原理:
初始状态:
Effect deps链表: [Link1(v=3)] ⇄ [Link2(v=-1)] ⇄ [Link3(v=2)]
执行过程:
1. 所有Link.version设为-1 (prepareDeps阶段)
2. 执行过程中使用的Link同步为当前dep.version
3. cleanupDeps检查:
- Link1: version=3 ≠ -1 → 保留 ✓
- Link2: version=-1 → 清理 ✗
- Link3: version=2 ≠ -1 → 保留 ✓
最终状态:
Effect deps链表: [Link1] ⇄ [Link3]
⚡ 性能优化策略图示
批处理机制
多个更新的批处理流程:
更新1: depA.trigger() ──┐
更新2: depB.trigger() ──┼──▶ 加入批处理队列
更新3: depC.trigger() ──┘
↓
startBatch()
↓
检查 batchedSub 队列
↓
逆序执行所有副作用
Effect3.run() ← depC
Effect1.run() ← depA
Effect2.run() ← depB
↓
endBatch()
版本号优化
全局版本号优化机制:
全局版本: globalVersion = 5
ComputedA (globalVersion = 5) ──┐
ComputedB (globalVersion = 3) ──┼──▶ refreshComputed检查
ComputedC (globalVersion = 5) ──┘
执行流程:
1. 检查 globalVersion 是否匹配
2. ComputedA: 5 === 5 → 跳过 ✓
3. ComputedB: 3 !== 5 → 需要刷新 ✗
4. ComputedC: 5 === 5 → 跳过 ✓
🎯 响应式对象代理策略
Proxy Handler 拦截点
对象属性访问拦截:
get(target, key, receiver):
├── 特殊标志位处理 (SKIP, IS_REACTIVE等)
├── 数组方法拦截 (includes, indexOf等)
├── 依赖收集 track(target, key)
├── ref自动解包
└── 嵌套对象递归代理
set(target, key, value, receiver):
├── 值预处理 (toRaw转换)
├── ref赋值特殊处理
├── Reflect.set执行设置
└── 条件触发 trigger(target, key)
集合类型特殊处理
Map/Set 集合处理器:
Map.get(key):
├── key 和 rawKey 双重追踪
├── 值的响应式包装
└── 嵌套处理
Map.set(key, value):
├── 值预处理
├── 检查是否存在key
├── Reflect.set执行
└── 根据情况触发ADD/SET
size/getter:
└── 追踪ITERATE_KEY依赖
📈 运行时交互示例
完整更新循环示例
示例代码执行过程:
const state = reactive({ count: 0 })
const double = computed(() => state.count * 2)
watch(double, (newVal) => console.log(newVal))
console.log(double.value)
↓
1. double.get() → refreshComputed
2. 执行 () => state.count * 2
3. 访问 state.count → track收集依赖
4. 建立 double → state.count 的依赖关系
5. 返回 0
state.count = 1
↓
1. Proxy.set拦截
2. trigger(state, 'count')
3. 通知double的dep
4. double标记为DIRTY
5. batch(double)
6. endBatch执行double的effect
7. 重新计算double.value = 2
8. 触发watch回调打印2
内存管理示例
依赖关系自动清理:
初始状态:
Effect deps: [state.count] ⇄ [state.name] ⇄ [state.age]
执行条件渲染:
if (showName) {
console.log(state.name) // 只访问name
}
下次更新:
1. prepareDeps: 所有version = -1
2. 执行effect: 只访问state.name
3. cleanupDeps:
- state.count: version = -1 → 清理
- state.name: version = current → 保留
- state.age: version = -1 → 清理
结果:
Effect deps: [state.name] // 自动清理未使用依赖
🎨 可视化最佳实践
设计模式总结
Vue 3响应式系统的三大核心模式:
1. 观察者模式 (Observer Pattern)
Subject(Observable) ←→ Observer
Dep ←→ Subscriber(Effect/Computed)
2. 代理模式 (Proxy Pattern)
RealSubject ← Proxy ← Client
Target ← Proxy ← User Code
3. 发布-订阅模式 (Pub-Sub Pattern)
Publisher → Event Channel → Subscriber
trigger() → batch queue → run()
优势:
✅ 解耦合: 数据变化与副作用执行分离
✅ 精确更新: 只更新真正受影响的部分
✅ 自动管理: 依赖关系自动建立和清理
✅ 性能优化: 批处理和版本号快速路径