第 16 题:Vue3 响应式原理深度解析(Proxy + effect 栈 + 依赖追踪)
🎯 一、核心问题
问:Vue3 响应式是如何实现的?Proxy、effect 栈和依赖追踪是怎么协作的?
这是高频面试深度题,面试官一般会追问 "为什么 Vue3 性能比 Vue2 好"。
🎯 二、标准回答(面试官满意版)
-
响应式核心是 Proxy
- Vue3 不再使用 defineProperty,而是使用 Proxy 代理对象
- Proxy 可以拦截
get、set、deleteProperty等操作 - 支持新增属性、数组下标变化、删除属性等
-
依赖收集(Track)
- 当访问响应式对象的属性时,Proxy 的
get会被触发 - Vue 内部将当前执行的 effect(函数)记录到 依赖集合
- 这样当属性变化时,可以精准触发依赖的 effect
- 当访问响应式对象的属性时,Proxy 的
-
effect 栈
- Vue3 用栈结构维护当前激活的 effect
- 当一个 effect 执行时,push 到栈顶
- 在
get触发时,依赖收集使用栈顶 effect - 结束后 pop 出栈
- 解决嵌套 effect 的依赖追踪问题
-
触发依赖(Trigger)
- 当属性通过 Proxy
set改变时 - Vue 会查找依赖集合,并依次执行 effect
- 实现组件重新渲染或 computed 更新
- 当属性通过 Proxy
🎯 三、简化流程图
scss
响应式对象被访问
│
▼
Proxy get 拦截
│
▼
track(effect) 收集依赖
│
▼
数据变化
│
▼
Proxy set 拦截
│
▼
trigger(effect) 触发依赖执行
🎯 四、示例代码(原理演示)
javascript
import { reactive, effect } from 'vue'
const state = reactive({ count: 0 })
effect(() => {
console.log('count =', state.count)
})
state.count++ // 自动触发 effect,打印最新值
解释:
reactive创建 Proxyeffect包裹回调函数并入栈- 访问
state.count→ track 收集依赖 - 修改
state.count→ trigger 执行 effect
🎯 五、面试官常见追问(高频)
追问 1:为什么 Vue3 使用 Proxy,比 Vue2 defineProperty 性能更好?
- 不需要递归遍历整个对象(惰性代理)
- 支持新增 / 删除属性、数组下标
- 更少内存开销
- 依赖收集更精准,减少无效更新
追问 2:effect 栈有什么作用?
- 支持嵌套 effect
- 避免误收集 effect
- 保证 track 时总是收集当前激活的 effect
追问 3:依赖追踪如何避免重复收集?
- 每个属性依赖使用 Set 保存 effect
- 同一个 effect 不会重复加入依赖集合
追问 4:computed 是怎么利用 effect 栈的?
- computed 内部也用 effect 包裹 getter
- effect 栈保证依赖收集在计算时有效
- 依赖变化时,computed 被标记 dirty,下次访问重新计算
追问 5:响应式循环引用怎么办?
- Vue3 Proxy 本身支持循环对象
- 每次 reactive 调用会 缓存已代理对象
- 避免重复代理和无限递归
🎯 六、一句话总结(面试官必背)
Vue3 响应式原理:通过 Proxy 拦截对象操作 + effect 栈管理当前执行上下文 + track/trigger 精准收集依赖,实现高性能、可缓存、可嵌套的响应式系统。