◆
Vue3 reactive 代理与依赖收集完整流程
前置流程
- 首先判断是否为对象
- 会有一个 map 变量去存储被
reactive代理过的对象,已经被reactive代理过的,直接return - 如果上述没有,进入到
proxy进行代理- 进行代理时,需要传入一个
handler,handler主要处理set与get - 在
get时,通过Reflect.get拿到target对应的key值 - 由于
readonly的实现也基本上是通过这个handler,但是由于是只读,所以不需要进行依赖收集 - 接下来如果不是
readonly那么进行依赖收集
- 进行代理时,需要传入一个
依赖收集
- 依赖收集需要一个数据结构去存储当前的依赖,如
targetMap,结构如下 - 它是一个
weakMap对象,它的key就是被代理的对象,value又是一个map对象 value对象的map对象,key是,被代理对象的属性值,value则是一个Set对象value 中的set对象,主要存储的是什么呢?就是当前这个响应式对象的属性值相对应要执行的方法,也就是用户外部定义的方法
WeakMap = {
源对象
Map:[
{
"key": "name",
"value": Set[ReactiveEffect]
},
{
"key": "age",
"value" Set[ReactiveEffect]
}
]
}
- 接着进入到依赖收集函数,首先会有一个判断当前是否需要进行依赖收集
- 这里就需要注意了,依赖收集是什么时候进行的呢,只是定义
reactive需要进行依赖收集吗? - 当然进行依赖收集的时候一定是我们获取
target对象属性的时候,也就是调用了get方法的时候 - 相当于我们要触发用户使用到
get的地方,也就是用户使用时的代码
- 这里就需要注意了,依赖收集是什么时候进行的呢,只是定义
- 我们会使用一个
effect函数去触发用户执行的代码。 - 在这个函数内我们做了什么操作呢?我们去实例化一个
ReactiveEffect类- 这个类又是干什么的呢?我们在这个类中增加了一个
run方法 - Todo active
- 在
run方法内有一个shouldTrack表示,当前需要收集依赖,我们将此变量置位true - 同时在运行
run方法时,我们将当前的这个ReactiveEffect类的值赋给一个变量activeEffect - 当上述两步操作完成后,我们执行用户外部传入的操作
reactive数据的方法fn - 一般在执行用户传入的
fn方法时,都会涉及到获取reactive的数据,即调用proxy的get,或者设置数据调用了proxy的set - 这是我们先分析
get因为在get中我们要开始进行依赖收集了,所以首先我们要判断是否执行了 effect 如果没有执行是不需要进行依赖收集的,我们用shouldTrack为true以及activeEffect有值表示当前应该进行依赖收集
- 这个类又是干什么的呢?我们在这个类中增加了一个
- 进行依赖收集时,要判断当前的对象是否已经在依赖收集的
targetMap中 - 如果当前的对象不在
targetMap中说明之前没有对此对象进行依赖收集,那么我们将要在targetMap添加它,key为target,value是一个空map对象(new Map()) - 然后如果当前的对象在
targetMap中,则取出它对应的value假设为depsMap - 然后我们要从
depsMap中获取当前指定属性对应的value值,假设这个获取到的值为dep - 如果当前对象没有进行过依赖收集或者当前对象进行过依赖收集,但是当前的这个属性没有进行收集过,则我们给
dep一个默认值new Set() - 如果当前的对象对应的属性没有进行过依赖收集,那么当前的
dep是一个空Set集合,这时候我们吧当前的activeEffect也就是ReactiveEffect添加到这个set中 - 同时我们给
activeEffect中的一个deps属性添加这个dep - 如果当前的对象对应的属性进行过依赖收集,我们去判断这个 dep 是否已经添加过
activeEffect如果已经添加过,则不需要继续添加了 - 至此依赖收集完毕
触发收集的依赖
- 收集依赖最终是为了进行触发,什么情况下触发呢,肯定是在
set操作中进行触发 - 首先我们在触发依赖时,需要从
targetMap中获取当前的代理对象 - 当我们获取到当前的代理对象时,我们需要获取当前代理对象的对应属性对应的
value也就是dep值 dep值是一个set集合,我们将其转换为数组后,进行循环执行里面的run方法,也就是用户外部的方法
一些注意的点
reactive进行代理的时候如果获取到的值是对象,则再进行一次reactive代理,这样就实现了深层次的代理- 基于以上的思路有些
api的设计理解起来就比较简单了
readonly
相当于在 reactive 进行 proxy 代理,触发 get 时,不对其进行依赖收集,因为其不需要触发 trigger
然后我们在 set 时抛出一个警告即可
shallowReactive && shallowReadonly
相当于在 reactive 代理时,如果获取到的是对象,则下面的对象没有进行 proxy 代理,也就是下面的深层次对象不是响应式的
toRaw
isProxy isReactive isReadonly
我们创建一个枚举值用来判断当前的数据类型
export const enum ReactiveFlags {
IS_REACTIVE = '__v_isReactive',
IS_READONLY = '__v_isReadonly',
RAW = '__v_raw',
}

还没有留言,来发表第一条吧~