1032 字
5 分钟
Vue3 响应式系统

题目描述
实现 Vue3 响应式系统核心功能:
reactive()
创建深层响应式对象effect()
注册副作用函数并自动追踪依赖- 依赖自动收集和触发更新机制
- 处理嵌套 effect 场景
- 支持分支切换优化 要求实现响应式数据劫持、依赖收集、触发更新等核心机制。
解题思路
- 代理拦截:使用 Proxy 拦截对象 get/set 操作
- 依赖管理:建立 WeakMap→Map→Set 三级依赖存储结构
- 副作用函数:effect 封装回调并自动追踪依赖
- 嵌套处理:使用栈结构管理嵌套 effect
- 依赖清理:每次执行前清除旧依赖,避免无效更新
关键洞察
- 精准依赖追踪:三级映射结构确保属性级依赖收集
- 异步更新优化:微任务队列合并多次更新
- 内存安全管理:WeakMap 自动释放无引用对象
- 嵌套场景处理:effect 栈保持当前执行上下文
- 分支切换优化:清理旧依赖解决条件分支问题
代码流程
flowchart TD A[reactive创建响应式对象] -->|Proxy代理| B subgraph 依赖收集 B[对象属性访问] --> C[track收集当前effect] end subgraph 触发更新 D[对象属性修改] --> E[trigger通知相关effects] end F[effect注册] --> G[初始化执行] G --> H[建立依赖关系] E -->|调度| I[执行effect]
代码实现
// 存储副作用函数的桶const bucket = new WeakMap()
// 当前激活的effectlet activeEffect = null
// effect调用栈const effectStack = []
// 创建响应式对象function reactive(target) { return new Proxy(target, { get(target, key, receiver) { track(target, key) return Reflect.get(target, key, receiver) }, 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 } })}
// 追踪依赖function track(target, key) { if (!activeEffect) return // 获取对象的依赖映射 let depsMap = bucket.get(target) if (!depsMap) { bucket.set(target, (depsMap = new Map())) } // 获取属性的依赖集合 let deps = depsMap.get(key) if (!deps) { depsMap.set(key, (deps = new Set())) } // 将当前effect添加到依赖集合 deps.add(activeEffect) // 将依赖集合添加到effect的deps中(用于清理) activeEffect.deps.push(deps)}
// 触发更新function trigger(target, key) { const depsMap = bucket.get(target) if (!depsMap) return const effects = depsMap.get(key) if (!effects) return // 创建新Set避免无限循环 const effectsToRun = new Set() effects.forEach(effectFn = >{ if (effectFn !== activeEffect) { effectsToRun.add(effectFn) } }) // 异步执行更新 queueMicrotask(() = >{ effectsToRun.forEach(effectFn = >{ effectFn() }) })}
// 副作用函数function effect(fn) { const effectFn = () = >{ // 清理旧依赖 cleanup(effectFn) // 设置当前激活的effect activeEffect = effectFn effectStack.push(effectFn) // 执行副作用函数 fn() // 恢复之前的effect effectStack.pop() activeEffect = effectStack[effectStack.length - 1] } // 存储依赖集合 effectFn.deps = [] // 立即执行 effectFn() return effectFn}
// 清理依赖function cleanup(effectFn) { for (const dep of effectFn.deps) { dep.delete(effectFn) } effectFn.deps.length = 0}
使用示例
// 创建响应式对象const obj = reactive({ count: 0, text: 'hello'})
// 注册副作用函数effect(() = >{ console.log(`Count: $ { obj.count }`)})
// 嵌套effect示例effect(() = >{ console.log('Outer effect')
effect(() = >{ console.log(`Inner effect: $ { obj.text }`) })})
// 分支切换示例effect(() = >{ console.log(obj.count > 0 ? obj.text: 'count is zero')})
// 测试响应式更新obj.count++ // 触发更新obj.text = 'world' // 触发更新// 输出结果:// Count: 0// Outer effect// Inner effect: hello// count is zero//// Count: 1// Inner effect: world// world
业务场景
- 组件状态管理:驱动Vue组件数据响应式更新
- 自动DOM更新:数据变化触发视图重新渲染
- 状态监听:实现watch/watchEffect基础能力
- 数据绑定:表单输入与状态自动同步
- 派生状态:基于其他状态自动计算新值
相似题目
- 实现 ref 响应式引用(中等) 核心:对象包装 + value属性拦截
- 实现 computed 计算属性(中等) 核心:懒计算 + 结果缓存
- 实现 Vue2 响应式系统(中等) 核心:Object.defineProperty + 递归劫持
- 实现观察者模式(简单) 核心:Subject/Observer 接口
- 实现 Promise A+规范(困难) 核心:状态机 + 异步回调管理