认识
一、认识
reactive
主要工作如下:
-
创建
Proxy
代理对象 -
访问时通过
track
收集依赖 -
设置时通过
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
的局限性如下:
-
Proxy
只可以代理引用类型数据 -
Proxy
代理对象解构之后的属性将不会触发handler
2.2 WeakMap
弱引用 不会影响垃圾回收机制。WeakMap
键为弱引用,如下所示 当 obj
置为 null
时,WeakMap
键没有对 obj
的地址保持引用,所以会触发垃圾回收机制回收
2.3 reactiveMap
reactiveMap
为 cosnt 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 集合
}
}