跳到主要内容

认识

2023年06月10日
柏拉文
越努力,越幸运

一、认识


reactive 主要工作如下:

  1. 创建 Proxy 代理对象

  2. 访问时通过 track 收集依赖

  3. 设置时通过 trigger 触发依赖

二、细节


2.1 Proxy

reactive 的实现原理如下:

const obj = reactive({});

function reactive(target){
const baseHandlers = {
get: ()=>{

},
set: ()=>{

}
}
return new Proxy(target,baseHandlers);
}

我们可以知道, reactive 本质上其实就是一个 Proxy 代理对象, Proxy 只接收引用类型数据, 传入基础数据会报错。因此, reactive 也只可以接收引用数据类型

Proxy 的局限性如下:

  1. Proxy 只可以代理引用类型数据

  2. Proxy 代理对象解构之后的属性将不会触发 handler

2.2 WeakMap

弱引用 不会影响垃圾回收机制。WeakMap弱引用,如下所示 当 obj 置为 null 时,WeakMap 键没有对 obj 的地址保持引用,所以会触发垃圾回收机制回收

2.3 reactiveMap

reactiveMapcosnt reactiveMap = new WeakMap() WeakMap 类型, 以 target 源对象为 target, 代理对象为 value。这样做的目的是: 一旦 target 源对象不存在,代理对象随即会被垃圾回收器回收,进而优化性能,减少了内存占用。

2.4 activeEffect

activeEffect 记录当前激活的 ReactiveEffect 实例, 如果存在 activeEffect , 说明注册了 fn 副作用函数,需要进行依赖收集。

2.5 依赖收集 track

所谓的响应性指的是: 当响应性数据触发 setter 时执行 fn 函数。那么需要在 getter 时能够收集当前的 fn 函数,以便在 setter 的时候可以执行对应的 fn 函数。但是对于收集而言, 如果仅仅是把 fn 存起来还是不够的,我们需要知道: 当前的这个 fn 是与哪个响应式数据对象的哪个属性对应的。只有这样,我们才可以在该属性触发 setter 的时候,准确的执行响应性。

因此,我们在依赖收集的时候,需要将 fn响应式对象的具体属性 绑定,那么如何精准的绑定呢?

track 单一依赖收集

WeakMap: {
key: 响应性对象,
value: Map 对象
{
key: 响应性对象指定属性,
value: 单个 ReactiveEffect
}
}

const targetMap = new WeakMap();
const depsMap= targetMap.get(target);
if(!depsMap){
targetMap.set(target, (depsMap = new Map()));
}
depsMap.set(key, activeEffect);

通过构建以上数据结构,我们就可以精准的绑定 fn响应式对象的具体属性。但是,如果一个属性有多个 ReactiveEffect , 以上实现会使后面 ReactiveEffect 覆盖前面的 ReactiveEffect。因此, 我们需要支持收集多个依赖。

track 多个依赖收集

WeakMap: {
key: 响应性对象,
value: Map 对象
{
key: 响应性对象指定属性,
value: ReactiveEffect 实例的 Set 集合
}
}

const targetMap = new Weakmap();
const depsMap = targetMap.get(target);
if(!depsMap){
targetMap.set(target, (depsMap = new Map()));
}
const dep = depsMap.get(key);
if(!dep){
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect);

2.6 依赖触发 trigger

trigger 单一依赖触发

const depsMap = targetMap.get(target);
if(!depsMap){
return;
}
const effect = depsMap.get(key) as ReactiveEffect;
effect?.fn();

trigger 多个依赖触发

const depsMap = targetMap.get(target);
if(!depsMap){
return;
}
const deps = depsMap.get(key);
if(!deps){
return;
}

for(const dep of deps){
dep.run();
}

2.7 依赖存储 targetMap

存储结构

WeakMap: {
key: 响应性对象,
value: Map 对象
{
key: 响应性对象指定属性,
value: ReactiveEffect 实例的 Set 集合
}
}