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 为例,它定义了 get、set 等陷阱:
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. 响应式系统的闭环流程
- 初始化:
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 的响应式系统实现了高效、精确的依赖追踪与更新触发。