发布网友 发布时间:2024-09-26 08:23
共1个回答
热心网友 时间:2024-10-25 03:59
如题,本文是我在阅读reactive源码实现过程的记录:
创建响应式对象:function?reactive(target:?object)?{??//?如果原始对象只读??if?(isReadonly(target))?{????return?target??}??//?创建响应式对象??return?createReactiveObject(????target,????false,????mutableHandlers,????mutableCollectionHandlers,????reactiveMap??)}function?createReactiveObject(??target:?Target,??isReadonly:?boolean,??baseHandlers:?ProxyHandler<any>,??collectionHandlers:?ProxyHandler<any>,??proxyMap:?WeakMap<Target,?any>)?{??//?非对象??if?(!isObject(target))?{????return?target??}??//?target?已经有对应的响应式对象代理,直接返回代理对象??const?existingProxy?=?proxyMap.get(target)??if?(existingProxy)?{????return?existingProxy??}??const?proxy?=?new?Proxy(????target,????//?用?reactive?创建的响应式对象?targetType?===?TargetType.COLLECTION?的结果是?false????targetType?===?TargetType.COLLECTION???collectionHandlers?:?baseHandlers??)??//?存储代理对象??proxyMap.set(target,?proxy)??//?返回代理对象??return?proxy}从上面代码可以看出reactive是通过调用createReactiveObject函数来创建响应式对象的,它的执行过程如下:
判断target是不是一个对象,如果不是直接返回target。
判断proxyMap中是否已经存在target对象的代理对象,如果有直接返回target对象。
通过newProxy对target配置代理,返回代理对象并赋值给变量proxy。
将代理对象proxy存入proxyMap。
返回proxy对象,我们在业务代码实际访问到的就是它。
proxyMap:它是一个WeakMap,在reactive创建响应式对象的过程中起到了性能优化的作用。通过proxyMap.get(target)获取已经创建好的proxy,如果有的话,就不需要再次创建了。WeakMap?持有的是每个键对象的“弱引用”,这意味着在没有其他引用存在时垃圾回收能正确进行WeakMap说明
追踪依赖项function?createReactiveObject(??target:?Target,??isReadonly:?boolean,??baseHandlers:?ProxyHandler<any>,??collectionHandlers:?ProxyHandler<any>,??proxyMap:?WeakMap<Target,?any>)?{??const?proxy?=?new?Proxy(????target,????//?用?reactive?创建的响应式对象?targetType?===?TargetType.COLLECTION?的结果是?false????targetType?===?TargetType.COLLECTION???collectionHandlers?:?baseHandlers??)??//?返回代理对象??return?proxy}上面这段代码只保留了createReactiveObject中将target包装成响应式对象的代码,响应式的实现都包含在Proxy的handler参数里,这儿对应的就是baseHandlers。
const?get?=?/*#__PURE__*/?createGetter()//?basehandlersconst?mutableHandlers:?ProxyHandler<object>?=?{??//?get?操作,用来获取?reactive?对象上的值,?需要跟踪的依赖项包含在这个函数里面。??get,??//?set?操作,用来更新?reactive?对象上的值,触发更新包含在这个函数里面。??set,??deleteProperty,??has,??ownKeys}从上面代码能够看出来,basehandlers.get就是createGetter函数的返回值,下面开始分析这个函数的实现
function?createGetter(isReadonly?=?false,?shallow?=?false)?{??return?function?get(target:?Target,?key:?string?|?symbol,?receiver:?object)?{????const?targetIsArray?=?isArray(target)????if?(!isReadonly?&&?targetIsArray?&&?hasOwn(arrayInstrumentations,?key))?{??????return?Reflect.get(arrayInstrumentations,?key,?receiver)????}????//?获取实际的值?????const?res?=?Reflect.get(target,?key,?receiver)????//?不是只读属性????if?(!isReadonly)?{??????//?在这个函数里面收集依赖??????track(target,?TrackOpTypes.GET,?key)????}????//?res?是一个?ref????if?(isRef(res))?{??????//?ref?unwrapping?-?does?not?apply?for?Array?+?integer?key.??????const?shouldUnwrap?=?!targetIsArray?||?!isIntegerKey(key)??????return?shouldUnwrap???res.value?:?res????}????//?res?是一个对象????if?(isObject(res))?{??????//?Convert?returned?value?into?a?proxy?as?well.?we?do?the?isObject?check??????//?here?to?avoid?invalid?value?warning.?Also?need?to?lazy?access?readonly??????//?and?reactive?here?to?avoid?circular?dependency.??????//?不是只读的话,将?res?也包装成一个响应式对象??????return?isReadonly???readonly(res)?:?reactive(res)????}????return?res??}}收集依赖的入口就在track函数,下面分析这个函数的具体实现:
function?track(target:?object,?type:?TrackOpTypes,?key:?unknown)?{??//?默认这个判断通过??if?(shouldTrack?&&?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()))????}????const?eventInfo?=?__DEV__????????{?effect:?activeEffect,?target,?type,?key?}??????:?undefined????trackEffects(dep,?eventInfo)??}}变量介绍:
targetMap:一个全局变量,用来存储target对应的依赖的集合,后续触发更新也会用到它。
depsMap:target对应的依赖集合,里面包含了与key对应的dep集合。
dep:用来收集依赖的集合。
targetMap的结构图示:track函数的执行过程也是比较清晰的:
通过targetMap.get(target)获取target对应的依赖集合,并赋值给depsMap。
如果depsMap不存在,执行targetMap.set(target,(depsMap=newMap())),构造一个空的map对象赋值给depsMap变量,存储到targetMap的target键上。
执行depsMap.get(key)获取depsMap上key对应Dep对象,如果不存在,调用createDep构造一个Dep对象,赋值给dep变量,存储到depsMap的key键上。
调用trackEffects追踪依赖项。
不管是reactive还是ref它们的依赖收集都是在trackEffects中完成的
export?function?trackEffects(??dep:?Dep,??debuggerEventExtraInfo?:?DebuggerEventExtraInfo)?{??let?shouldTrack?=?false??if?(effectTrackDepth?<=?maxMarkerBits)?{????if?(!newTracked(dep))?{??????dep.n?|=?trackOpBit?//?set?newly?tracked??????shouldTrack?=?!wasTracked(dep)????}??}?else?{????//?Full?cleanup?mode.????shouldTrack?=?!dep.has(activeEffect!)??}??if?(shouldTrack)?{????dep.add(activeEffect!)????activeEffect!.deps.push(dep)??}}通知依赖项更新我们对响应式对象的属性重新赋值的时候会触发页面更新、computed或者watch重新计算或者执行,这里的核心其实就是通知依赖项更新的过程。通知更新的入口就在createSetter的返回函数中:
const?set?=?/*#__PURE__*/?createSetter()function?createSetter(shallow?=?false)?{??return?function?set(????target:?object,????key:?string?|?symbol,????value:?unknown,????receiver:?object??):?boolean?{????//?旧值????let?oldValue?=?(target?as?any)[key]????if?(isReadonly(oldValue)?&&?isRef(oldValue)?&&?!isRef(value))?{??????return?false????}????if?(!shallow?&&?!isReadonly(value))?{??????if?(!isShallow(value))?{????????value?=?toRaw(value)????????oldValue?=?toRaw(oldValue)??????}??????if?(!isArray(target)?&&?isRef(oldValue)?&&?!isRef(value))?{????????oldValue.value?=?value????????return?true??????}????}?else?{??????//?in?shallow?mode,?objects?are?set?as-is?regardless?of?reactive?or?not????}????//?是否拥有传入的?key,只判断?target?本身,忽略原型????const?hadKey?=??????isArray(target)?&&?isIntegerKey(key)??????????Number(key)?<?target.length????????:?hasOwn(target,?key)????//?赋值????const?result?=?Reflect.set(target,?key,?value,?receiver)????//?don't?trigger?if?target?is?something?up?in?the?prototype?chain?of?original????if?(target?===?toRaw(receiver))?{??????//?通知依赖更新??????if?(!hadKey)?{????????trigger(target,?TriggerOpTypes.ADD,?key,?value)??????}?else?if?(hasChanged(value,?oldValue))?{????????trigger(target,?TriggerOpTypes.SET,?key,?value,?oldValue)??????}????}????return?result??}}通过hadkey判断target是否拥有传入的属性,这里会忽略掉target原型上的属性,如果是操作原型则不会后续触发更新流程。通知依赖更新的入口函数就是tigger函数
export?function?trigger(??target:?object,??type:?TriggerOpTypes,??key?:?unknown,??newValue?:?unknown,??oldValue?:?unknown,??oldTarget?:?Map<unknown,?unknown>?|?Set<unknown>)?{??//?target?对应的依赖集合??const?depsMap?=?targetMap.get(target)??if?(!depsMap)?{????//?never?been?tracked????return??}??let?deps:?(Dep?|?undefined)[]?=?[]?//?是数组?if?(key?===?'length'?&&?isArray(target))?{????depsMap.forEach((dep,?key)?=>?{??????if?(key?===?'length'?||?key?>=?(newValue?as?number))?{????????deps.push(dep)??????}????})??}?else?{????//?schedule?runs?for?SET?|?ADD?|?DELETE????if?(key?!==?void?0)?{??????//?将?despMap?中?key?对应的?dep?集合取出??????deps.push(depsMap.get(key))????}????//?添加?iterate?到?deps?中????switch?(type)?{??????case?TriggerOpTypes.ADD:????????if?(!isArray(target))?{??????????deps.push(depsMap.get(ITERATE_KEY))??????????if?(isMap(target))?{????????????deps.push(depsMap.get(MAP_KEY_ITERATE_KEY))??????????}????????}?else?if?(isIntegerKey(key))?{??????????//?new?index?added?to?array?->?length?changes??????????deps.push(depsMap.get('length'))????????}????????break??????case?TriggerOpTypes.DELETE:????????if?(!isArray(target))?{??????????deps.push(depsMap.get(ITERATE_KEY))??????????if?(isMap(target))?{????????????deps.push(depsMap.get(MAP_KEY_ITERATE_KEY))??????????}????????}????????break??????case?TriggerOpTypes.SET:????????if?(isMap(target))?{??????????deps.push(depsMap.get(ITERATE_KEY))????????}????????break????}??}??//?通知?deps?收集到的所有依赖项更新???if?(deps.length?===?1)?{????if?(deps[0])?{???????triggerEffects(deps[0])????}??}?else?{?????//?正常情况下不会进入else,省略这部分代码??}?}export?function?triggerEffects(??dep:?Dep?|?ReactiveEffect[],??debuggerEventExtraInfo?:?DebuggerEventExtraInfo)?{??//?spread?into?array?for?stabilization??const?effects?=?isArray(dep)???dep?:?[...dep]??for?(const?effect?of?effects)?{????if?(effect.computed)?{??????triggerEffect(effect,?debuggerEventExtraInfo)????}??}??for?(const?effect?of?effects)?{????if?(!effect.computed)?{??????triggerEffect(effect,?debuggerEventExtraInfo)????}??}}function?triggerEffect(??effect:?ReactiveEffect,??debuggerEventExtraInfo?:?DebuggerEventExtraInfo)?{??if?(effect?!==?activeEffect?||?effect.allowRecurse)?{????if?(__DEV__?&&?effect.onTrigger)?{??????effect.onTrigger(extend({?effect?},?debuggerEventExtraInfo))????}????if?(effect.scheduler)?{??????effect.scheduler()????}?else?{??????effect.run()????}??}}trigger函数的逻辑很清晰:
targetMap.get(target)获取target对应的dep集合。
执行deps.push(depsMap.get(key))将key对应的dep集合push到deps数组。
调用triggerEffects遍历dep集合通知对应依赖更新。
原文:https://juejin.cn/post/7095640961115488269