手写 Vue 源码 === 完善依赖追踪与触发更新
目录
依赖收集的完整实现
trackEffects:建立双向依赖关系
触发更新的完整实现
完整的响应式流程
为什么使用 Map 而不是 Set?
总结
在上一篇文章中,我们介绍了 Vue3 响应式系统的基本原理和 activeEffect 的作用。现在,我们将深入探讨完善后的依赖追踪和触发更新机制,特别是 track、 trigger、 trackEffects 和 triggerEffects 函数的实现,以及 ReactiveEffect 类中新增的属性。
class ReactiveEffect {_trackId = 0; // 当前的 effect 执行了几次deps = []; // 当前的 effect 依赖了哪些属性_depsLength = 0; // 当前的 effect 依赖的属性有多少个public active = true; //默认是响应式的constructor(public fn, public scheduler) {}// ...
}
这些新增的属性有重要的作用:
- _trackId:记录 effect 执行的次数,用于优化依赖收集
- deps:存储当前 effect 依赖的所有属性的依赖集合
- _depsLength:记录依赖的属性数量,避免频繁计算数组长度
依赖收集的完整实现
// 存储依赖收集的关系
const targetMap = new WeakMap();export const createDep = (cleanUp, key) => {const dep = new Map() as any; //创建的收集器还是一个mapdep.cleanUp = cleanUp; //清理方法dep.name = key; //收集器名称return dep;
};export function track(target, key) {if (activeEffect) {let depsMap = targetMap.get(target);if (!depsMap) {targetMap.set(target, (depsMap = new Map()));}let dep = depsMap.get(key);if (!dep) {depsMap.set(key, (dep = createDep(() => depsMap.delete(key), key)));}trackEffects(activeEffect, dep);console.log(targetMap);}
}
与之前相比,有几个重要的变化:
- 依赖集合从 Set 变成了 Map,这允许我们存储更多信息
- 使用