Vue3 的响应式系统源码级执行流程解析
字数 879 2025-11-12 02:00:44

Vue3 的响应式系统源码级执行流程解析

我们以 reactive 函数为例,深入源码执行流程,逐步分析响应式系统的实现机制。

1. 响应式入口:reactive 函数

当调用 reactive(target) 时,Vue3 会执行以下逻辑:

// 1. 检查是否只读响应式对象,否则调用 createReactiveObject
function reactive(target: object) {
  return createReactiveObject(target, false, mutableHandlers, mutableCollectionHandlers);
}

2. 创建响应式对象:createReactiveObject

此函数是响应式系统的核心初始化环节:

function createReactiveObject(target, isReadonly, baseHandlers, collectionHandlers) {
  // 2.1 若 target 是原始值(非对象),直接返回
  if (!isObject(target)) return target;

  // 2.2 若 target 已是代理对象,直接返回(避免重复代理)
  if (target[ReactiveFlags.RAW] && !(isReadonly && target[ReactiveFlags.IS_REACTIVE])) {
    return target;
  }

  // 2.3 检查缓存:若已有该 target 的代理,直接返回缓存结果
  const proxyMap = isReadonly ? readonlyMap : reactiveMap;
  const existingProxy = proxyMap.get(target);
  if (existingProxy) return existingProxy;

  // 2.4 根据 target 类型选择 handlers(普通对象用 baseHandlers,Set/Map 用 collectionHandlers)
  const handlers = isCollectionType(target) ? collectionHandlers : baseHandlers;

  // 2.5 创建 Proxy 实例
  const proxy = new Proxy(target, handlers);

  // 2.6 缓存代理对象(target -> proxy 映射)
  proxyMap.set(target, proxy);
  return proxy;
}

3. 处理器配置:baseHandlers 与依赖收集

以普通对象的 mutableHandlers 为例,它定义了 getset 等陷阱:

const mutableHandlers = {
  get: createGetter(),      // 依赖收集
  set: createSetter(),      // 触发更新
  deleteProperty,           // 处理 delete 操作
  has,                      // 处理 in 操作
  ownKeys                   // 处理 Object.keys 等迭代操作
};

3.1 createGetter 与依赖收集(Track)

function createGetter() {
  return function get(target, key, receiver) {
    // 3.1.1 处理内置符号(如 ReactiveFlags.IS_REACTIVE)
    if (key === ReactiveFlags.IS_REACTIVE) return true;

    // 3.1.2 反射获取原始值
    const res = Reflect.get(target, key, receiver);

    // 3.1.3 如果是符号或不可响应值,直接返回
    if (isSymbol(key) && builtInSymbols.has(key)) return res;

    // 3.1.4 依赖收集:将当前活跃的 effect(若有)与 target.key 建立关联
    track(target, key);

    // 3.1.5 若获取的值是对象,递归代理(懒代理)
    if (isObject(res)) {
      return reactive(res);
    }
    return res;
  };
}

3.2 track 函数如何存储依赖?

// 全局依赖存储结构
const targetMap = new WeakMap();  // target -> keyDepMap 的映射

function track(target, key) {
  if (!activeEffect) return;  // 无活跃 effect 则直接返回

  // 获取 target 对应的 keyDepMap(key -> depSet)
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()));
  }

  // 获取 key 对应的依赖集合(depSet)
  let dep = depsMap.get(key);
  if (!dep) {
    depsMap.set(key, (dep = new Set()));
  }

  // 将当前 activeEffect 添加到 dep 中
  dep.add(activeEffect);
  // 同时 effect 也记录其依赖的 dep(用于清理)
  activeEffect.deps.push(dep);
}

4. 更新触发:createSetter 与派发更新(Trigger)

function createSetter() {
  return function set(target, key, value, receiver) {
    // 4.1 检查操作类型(新增 or 修改)
    const hadKey = hasOwn(target, key);
    const oldValue = target[key];

    // 4.2 反射设置值
    const result = Reflect.set(target, key, value, receiver);

    // 4.3 仅当代理对象是原始对象的接收器时触发更新(避免由原型链触发)
    if (target === toRaw(receiver)) {
      if (!hadKey) {
        // 新增属性
        trigger(target, key, TriggerOpTypes.ADD, value);
      } else if (hasChanged(value, oldValue)) {
        // 修改属性且值发生变化
        trigger(target, key, TriggerOpTypes.SET, value);
      }
    }
    return result;
  };
}

4.4 trigger 函数如何触发更新?

function trigger(target, key, type, newValue) {
  // 4.4.1 从 targetMap 中获取 target 对应的 depsMap
  const depsMap = targetMap.get(target);
  if (!depsMap) return;

  // 4.4.2 创建 effects 集合,避免重复执行或递归触发
  const effects = new Set();
  const addEffects = (dep) => {
    if (dep) {
      dep.forEach(effect => effects.add(effect));
    }
  };

  // 4.4.3 根据 key 收集依赖(常规更新)
  addEffects(depsMap.get(key));

  // 4.4.4 处理特殊操作(如数组 length 变更、ADD/DELETE 操作)
  if (type === TriggerOpTypes.ADD || type === TriggerOpTypes.DELETE) {
    addEffects(depsMap.get(isArray(target) ? 'length' : undefined));
  }

  // 4.4.5 调度执行 effects
  effects.forEach(effect => {
    if (effect.options.scheduler) {
      effect.options.scheduler(effect);  // 异步调度(如 queueJob)
    } else {
      effect();  // 同步执行
    }
  });
}

5. 响应式系统的闭环流程

  1. 初始化reactive(target) → 创建 Proxy 代理并缓存。
  2. 取值(依赖收集):访问 obj.key → 触发 get 陷阱 → 调用 track 将当前 activeEffect 存入 targetMap
  3. 设值(派发更新):修改 obj.key → 触发 set 陷阱 → 调用 triggertargetMap 中找到关联的 effects → 通过调度器或直接执行 effect。
  4. 递归代理:嵌套对象在取值时被懒代理,确保深层响应性。

6. 关键设计亮点

  • 懒代理:嵌套对象在访问时才代理,避免不必要的性能开销。
  • 缓存机制:通过 reactiveMap 避免重复代理同一对象。
  • 调度器:支持异步更新(如 scheduler 中使用 queueJob 实现批处理)。
  • 类型区分:对 Set/Map 使用 collectionHandlers,处理其专属方法(如 adddelete)。

通过以上步骤,Vue3 的响应式系统实现了高效、精确的依赖追踪与更新触发。

Vue3 的响应式系统源码级执行流程解析 我们以 reactive 函数为例,深入源码执行流程,逐步分析响应式系统的实现机制。 1. 响应式入口: reactive 函数 当调用 reactive(target) 时,Vue3 会执行以下逻辑: 2. 创建响应式对象: createReactiveObject 此函数是响应式系统的核心初始化环节: 3. 处理器配置: baseHandlers 与依赖收集 以普通对象的 mutableHandlers 为例,它定义了 get 、 set 等陷阱: 3.1 createGetter 与依赖收集(Track) 3.2 track 函数如何存储依赖? 4. 更新触发: createSetter 与派发更新(Trigger) 4.4 trigger 函数如何触发更新? 5. 响应式系统的闭环流程 初始化 : reactive(target) → 创建 Proxy 代理并缓存。 取值(依赖收集) :访问 obj.key → 触发 get 陷阱 → 调用 track 将当前 activeEffect 存入 targetMap 。 设值(派发更新) :修改 obj.key → 触发 set 陷阱 → 调用 trigger 从 targetMap 中找到关联的 effects → 通过调度器或直接执行 effect。 递归代理 :嵌套对象在取值时被懒代理,确保深层响应性。 6. 关键设计亮点 懒代理 :嵌套对象在访问时才代理,避免不必要的性能开销。 缓存机制 :通过 reactiveMap 避免重复代理同一对象。 调度器 :支持异步更新(如 scheduler 中使用 queueJob 实现批处理)。 类型区分 :对 Set/Map 使用 collectionHandlers ,处理其专属方法(如 add 、 delete )。 通过以上步骤,Vue3 的响应式系统实现了高效、精确的依赖追踪与更新触发。