一. vue2和vue3的Proxy底层源码详细拆解

发布于:2025-02-13 ⋅ 阅读:(187) ⋅ 点赞:(0)

Vue3 在底层实现上确实通过 Proxy 的懒处理机制编译期的静态分析优化 解决了 Vue2 的性能问题,下面分两部分拆解其底层实现原理:


一、响应式系统:Proxy 的「惰性递归」实现

Vue3 的响应式核心是 Proxy + Reflect,通过 「访问时递归」 的机制实现按需响应式化。具体实现步骤如下:

1. 创建 Proxy 代理
function reactive(obj) {
  return new Proxy(obj, {
    get(target, key, receiver) {
      const res = Reflect.get(target, key, receiver);
      // 关键点:访问属性时才递归响应式化
      if (isObject(res)) {
        return reactive(res); // 递归响应式化
      }
      track(target, key); // 依赖收集
      return res;
    },
    set(target, key, value, receiver) {
      const result = Reflect.set(target, key, value, receiver);
      trigger(target, key); // 触发更新
      return result;
    }
  });
}

关键机制

  • 惰性递归:只有当访问到某个属性时(例如 obj.a.b),才会对 obj.a 进行响应式化,而不是初始化时递归全部属性
  • 依赖收集:在 get 中通过 track() 记录当前正在运行的 effect(副作用函数)
  • 触发更新:在 set 中通过 trigger() 通知所有关联的 effect 重新执行
2. 依赖关系存储结构
type Dep = Set<Effect>
type KeyToDepMap = Map<any, Dep>
const targetMap = new WeakMap<any, KeyToDepMap>()

// 数据结构示例:
targetMap: {
  [obj]: {
    [key]: [effect1, effect2, ...]
  }
}
  • WeakMap:用对象本身作为键,防止内存泄漏
  • 层级存储:每个对象的每个属性对应一个依赖集合(Set
3. 性能对比示例

假设有对象:

const data = { 
  a: { b: { c: 1 } }, 
  d: { e: 2 } 
}
  • Vue2:初始化时递归处理 a.b.cd.e,共 5 次 defineProperty
  • Vue3
    • 初始化时只处理 data 层(1 次 Proxy)
    • 如果代码中只访问 data.a.b.c
      • 访问 data.a 时处理 a 层(第 2 次 Proxy)
      • 访问 a.b 时处理 b 层(第 3 次 Proxy)
      • d.e 从未被处理


网站公告

今日签到

点亮在社区的每一天
去签到