🏗️ 核心架构概览
1. 响应式系统三层架构
text
┌─────────────────────────────────────────┐
│ 组件渲染系统 (Renderer) │
├─────────────────────────────────────────┤
│ 响应式系统 (Reactivity) │
│ ┌─────────────┐ ┌──────────────────┐ │
│ │ 依赖收集 │ │ 触发更新 │ │
│ │ (Track) │ │ (Trigger) │ │
│ └─────────────┘ └──────────────────┘ │
├─────────────────────────────────────────┤
│ 原始响应式对象 (Raw Objects) │
└─────────────────────────────────────────┘
🔄 Vue 2 vs Vue 3 响应式原理对比
2. Vue 2: Object.defineProperty
javascript
// Vue 2 响应式实现简化版
function defineReactive(obj, key, val) {
// 为每个属性创建 Dep(依赖收集器)
const dep = new Dep()
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
// 依赖收集
if (Dep.target) {
dep.depend() // 收集当前 watcher
}
return val
},
set(newVal) {
if (newVal === val) return
val = newVal
// 触发更新
dep.notify()
}
})
}
// 递归对象实现深度响应式
function observe(obj) {
if (typeof obj !== 'object' || obj === null) {
return
}
// 递归处理对象属性
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key])
})
}
// Vue 2 的局限性:
// 1. 无法检测对象属性的添加/删除
// 2. 数组变异方法需要特殊处理
// 3. 性能问题:递归遍历所有属性
3. Vue 3: Proxy + Reflect
javascript
// Vue 3 响应式实现简化版
function reactive(target) {
return createReactiveObject(target)
}
function createReactiveObject(target) {
// 创建响应式处理器
const handler = {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)
// 依赖收集
track(target, key)
// 深度响应式:如果值是对象,递归处理
if (typeof result === 'object' && result !== null) {
return reactive(result)
}
return result
},
set(target, key, value, receiver) {
const oldValue = target[key]
const result = Reflect.set(target, key, value, receiver)
// 只有值变化时才触发更新
if (oldValue !== value) {
// 触发更新
trigger(target, key)
}
return result
},
deleteProperty(target, key) {
const hasKey = hasOwn(target, key)
const result = Reflect.deleteProperty(target, key)
if (hasKey && result) {
// 触发更新
trigger(target, key)
}
return result
},
has(target, key) {
const result = Reflect.has(target, key)
track(target, key)
return result
},
ownKeys(target) {
track(target, ITERATE_KEY) // 追踪迭代操作
return Reflect.ownKeys(target)
}
}
return new Proxy(target, handler)
}
// Vue 3 的优势:
// 1. 支持对象属性的添加/删除
// 2. 更好的性能(惰性代理)
// 3. 支持 Map、Set 等集合类型
// 4. 更精细的依赖追踪
🎯 核心概念详解
4. 依赖收集 (Track)
javascript
// 全局的依赖收集栈
let activeEffect = null
const targetMap = new WeakMap() // 目标对象 → 键 → 依赖集合
function track(target, key) {
if (!activeEffect) return
// 获取目标对象的依赖映射
let depsMap = targetMap.get(target)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}
// 获取属性的依赖集合
let dep = depsMap.get(key)
if (!dep) {
depsMap.set(key, (dep = new Set()))
}
// 收集当前 effect
dep.add(activeEffect)
activeEffect.deps.push(dep) // 反向记录,用于清理
}
// Effect 类(相当于 Vue 2 的 Watcher)
class ReactiveEffect {
constructor(fn, scheduler) {
this.fn = fn
this.scheduler = scheduler
this.deps = [] // 依赖此 effect 的所有 dep
this.active = true
}
run() {
if (!this.active) return this.fn()
// 保存当前 effect,开始依赖收集
const lastEffect = activeEffect
activeEffect = this
try {
return this.fn()
} finally {
// 恢复之前的 effect
activeEffect = lastEffect
}
}
stop() {
if (this.active) {
// 清理所有依赖
cleanupEffect(this)
this.active = false
}
}
}
function cleanupEffect(effect) {
const { deps } = effect
deps.forEach(dep => {
dep.delete(effect)
})
deps.length = 0
}
5. 触发更新 (Trigger)
javascript
function trigger(target, key, type = 'SET') {
const depsMap = targetMap.get(target)
if (!depsMap) return
// 获取该属性的依赖 effects
const effects = depsMap.get(key)
// 获取迭代操作的依赖(用于 for...in, Object.keys 等)
const iterateEffects = depsMap.get(ITERATE_KEY)
const effectsToRun = new Set()
// 收集需要执行的 effects
if (effects) {
effects.forEach(effect => {
if (effect !== activeEffect) {
effectsToRun.add(effect)
}
})
}
// 对于添加/删除属性,需要触发迭代依赖
if (type === 'ADD' || type === 'DELETE') {
if (iterateEffects) {
iterateEffects.forEach(effect => {
if (effect !== activeEffect) {
effectsToRun.add(effect)
}
})
}
}
// 执行 effects
effectsToRun.forEach(effect => {
if (effect.scheduler) {
effect.scheduler() // 调度执行(用于 computed、watch)
} else {
effect.run() // 立即执行
}
})
}
⚡ 响应式 API 实现
6. ref 实现原理
javascript
class RefImpl {
constructor(value, shallow = false) {
this._value = shallow ? value : toReactive(value)
this._rawValue = value
this.__v_isRef = true
this._shallow = shallow
// 为 ref 创建依赖集合
this.dep = new Set()
}
get value() {
// 依赖收集
trackRefValue(this)
return this._value
}
set value(newVal) {
if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal
this._value = this._shallow ? newVal : toReactive(newVal)
// 触发更新
triggerRefValue(this)
}
}
}
function trackRefValue(ref) {
if (activeEffect) {
ref.dep.add(activeEffect)
activeEffect.deps.push(ref.dep)
}
}
function triggerRefValue(ref) {
const effects = ref.dep
effects.forEach(effect => {
if (effect.scheduler) {
effect.scheduler()
} else {
effect.run()
}
})
}
function toReactive(value) {
return isObject(value) ? reactive(value) : value
}
7. computed 实现原理
javascript
class ComputedRefImpl {
constructor(getter, setter) {
this._getter = getter
this._setter = setter
this._value = undefined
this._dirty = true // 脏检查标志
this.dep = new Set()
this.effect = new ReactiveEffect(
getter,
() => {
// 当依赖变化时,标记为脏
if (!this._dirty) {
this._dirty = true
// 触发依赖 computed 的 effects
triggerRefValue(this)
}
}
)
}
get value() {
// 依赖收集
trackRefValue(this)
// 如果脏了,重新计算
if (this._dirty) {
this._dirty = false
this._value = this.effect.run()
}
return this._value
}
set value(newVal) {
if (this._setter) {
this._setter(newVal)
} else {
console.warn('Write operation failed: computed value is readonly')
}
}
}
🔧 编译时优化
8. Patch Flags 优化
javascript
// 模板编译优化示例
// 编译前模板
<template>
<div>
<span>静态内容</span>
<span>{{ dynamic }}</span>
<div :class="className"></div>
</div>
</template>
// 编译后代码
import { createElementVNode as _createElementVNode } from "vue"
const _hoisted_1 = /*#__PURE__*/_createElementVNode(
"span",
null,
"静态内容",
-1 /* HOISTED */
)
export function render(_ctx, _cache) {
return _createElementVNode(
"div",
null, [
_hoisted_1, // 静态节点提升
_createElementVNode(
"span",
null,
_toDisplayString(_ctx.dynamic),
1 /* TEXT */
),
_createElementVNode(
"div",
{
class: normalizeClass(_ctx.className)
},
null,
2 /* CLASS */
)
],
0 /* 无标志 */
)
}
// Patch Flags 类型
const PatchFlags = {
TEXT: 1, // 动态文本
CLASS: 2, // 动态 class
STYLE: 4, // 动态 style
PROPS: 8, // 动态 props
FULL_PROPS: 16, // 动态 key,需要全量 diff
HYDRATE_EVENTS: 32,
STABLE_FRAGMENT: 64,
KEYED_FRAGMENT: 128,
UNKEYED_FRAGMENT: 256,
NEED_PATCH: 512,
DYNAMIC_SLOTS: 1024,
HOISTED: -1, // 静态提升
BAIL: -2 // 特殊情况
}
9. Tree Flattening(树结构打平)
javascri
// 优化前的 VNode 结构
{
type: 'div',
children: [
{ type: 'p', children: '静态内容' },
{ type: 'span', children: [/* 动态内容 */] },
{ type: 'div', children: [/* 更多嵌套 */] }
]
}
// 优化后的 VNode 结构
{
type: 'div',
children: [
{ type: 'p', children: '静态内容' },
// 动态节点被提取到单独的数组中
],
// 动态子节点被收集到这里
dynamicChildren: [
{ type: 'span', patchFlag: 1 },
{ type: 'div', patchFlag: 2 }
]
}
// 更新时只 diff dynamicChildren,跳过静态节点
📊 响应式性能优化
10. 依赖收集优化
javascr
// 1. 惰性依赖收集
let shouldTrack = true
function pauseTracking() {
shouldTrack = false
}
function enableTracking() {
shouldTrack = true
}
function track(target, key) {
if (!shouldTrack || !activeEffect) return
// ... 原有的 track 逻辑
}
// 2. 批量更新
let isFlushing = false
let queue = []
function queueJob(job) {
if (!queue.includes(job)) {
queue.push(job)
}
// 下一个 tick 执行所有更新
if (!isFlushing) {
isFlushing = true
Promise.resolve().then(() => {
try {
queue.forEach(job => job())
} finally {
queue.length = 0
isFlushing = false
}
})
}
}
// 3. 响应式层级的优化
const RAW = '__v_raw' // 原始对象标记
function toRaw(observed) {
const raw = observed && observed[RAW]
return raw ? toRaw(raw) : observed
}
// 避免深层代理的重复创建
const proxyMap = new WeakMap()
function createReactiveObject(target) {
// 检查是否已经有代理
const existingProxy = proxyMap.get(target)
if (existingProxy) {
return existingProxy
}
const proxy = new Proxy(target, handlers)
proxyMap.set(target, proxy)
return proxy
}
🔄 响应式系统的调度机制
11. 更新队列与调度器
javascri
// 响应式任务调度器
const queue = []
let isFlushing = false
const resolvedPromise = Promise.resolve()
function queueFlush() {
if (!isFlushing && !queue.length) {
isFlushing = true
resolvedPromise.then(flushJobs)
}
}
function flushJobs() {
try {
// 先执行所有前置任务
for (let i = 0; i < queue.length; i++) {
const job = queue[i]
if (job && job.active !== false) {
if (job.pre) {
job()
}
}
}
// 执行组件更新
for (let i = 0; i < queue.length; i++) {
const job = queue[i]
if (job && job.active !== false) {
if (!job.pre) {
job()
}
}
}
} finally {
// 清空队列
queue.length = 0
isFlushing = false
// 执行后置任务
// flushPostFlushCbs()
}
}
// watch 的调度实现
function watch(source, cb, options = {}) {
const { flush = 'sync' } = options
let scheduler
if (flush === 'sync') {
scheduler = job => job() // 同步执行
} else if (flush === 'pre') {
scheduler = job => queueJob(job) // 组件更新前
} else { // 'post'
scheduler = job => queuePostFlushCb(job) // 组件更新后
}
const effect = new ReactiveEffect(getter, scheduler)
// ...
}
🎯 响应式系统的边界情况
12. 循环引用处理
javascript
// 使用 WeakMap 避免循环引用
const reactiveMap = new WeakMap()
function reactive(obj) {
// 如果已经代理过,直接返回
const existing = reactiveMap.get(obj)
if (existing) return existing
// 如果对象有循环引用标记,跳过
if (obj && obj.__v_skip) {
return obj
}
const proxy = createReactiveObject(obj)
reactiveMap.set(obj, proxy)
return proxy
}
// 标记跳过响应式的对象
function markRaw(value) {
Object.defineProperty(value, '__v_skip', {
value: true,
enumerable: false,
configurable: true
})
return value
}
13. 大对象的性能优化
javascript
// 浅层响应式
function shallowReactive(target) {
return createReactiveObject(target, true)
}
function createReactiveObject(target, shallow = false) {
const handlers = shallow ? shallowHandlers : baseHandlers
// ...
}
// 浅层 handlers
const shallowHandlers = {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)
track(target, key)
// 关键区别:不递归处理嵌套对象
return result // 直接返回,不再包装
},
// ... 其他 handlers
}
// 惰性响应式:只在实际访问时进行代理
function lazyReactive(target) {
let proxyCache = null
return new Proxy(target, {
get(target, key, receiver) {
if (key === '__v_raw') return target
// 第一次访问时才创建真正的响应式代理
if (!proxyCache) {
proxyCache = reactive(target)
}
return Reflect.get(proxyCache, key, receiver)
},
// ... 其他操作
})
}
📈 响应式系统的监控与调试
14. 开发工具集成
javascri
// 响应式调试信息
function setupReactivityDebug() {
// 1. 跟踪依赖关系
const dependencyGraph = new Map()
// 2. 性能监控
const performance = {
trackTime: 0,
triggerTime: 0,
effectCount: 0
}
// 3. 内存泄漏检测
const effectRegistry = new WeakSet()
return {
// 暴露给 Vue DevTools 的接口
inspect(target) {
const depsMap = targetMap.get(target)
return {
deps: depsMap ? Array.from(depsMap.entries()) : [],
rawValue: toRaw(target),
isReactive: isReactive(target)
}
},
// 性能分析
getPerformance() {
return { ...performance }
},
// 清理所有 effect
disposeAll() {
// 清理逻辑
}
}
}
// Vue DevTools 中的响应式面板可以看到:
// 1. 响应式对象的依赖图
// 2. 每个属性的依赖列表
// 3. Effect 的执行历史
// 4. 性能分析数据
🎓 总结:Vue 响应式系统的演进
Vue 2 到 Vue 3 的关键改进:
- 底层实现 :
Object.defineProperty→Proxy - 性能:递归初始化 → 惰性代理
- 功能:不支持新增属性 → 完全支持
- 类型支持:有限的类型推断 → 完整的 TypeScript 支持
- 集合类型:不支持 Map/Set → 完整支持
核心创新点:
- 编译时优化:Patch Flags、Tree Flattening
- 依赖收集粒度:组件级 → 属性级
- 更新调度:同步更新 → 异步批量更新
- 内存管理:WeakMap 自动垃圾回收
设计哲学:
javascript
// Vue 响应式系统的设计目标:
1. 透明性:开发者无需手动管理依赖
2. 高效性:最小化的更新范围
3. 一致性:同步的编程模型,异步的更新执行
4. 渐进性:从简单到复杂的平滑过渡
5. 可调试性:完整的开发工具支持
// 这就是为什么 Vue 的响应式系统既强大又易用
Vue 的响应式系统是其框架的核心,它巧妙地将声明式编程 与高效的更新机制结合起来,为开发者提供了极佳的开发体验,同时保证了优秀的运行时性能。