Vue 3.0 - track与trigger的容器
前言
此文章为早期版本,可能与当前最新版本有出入,敬请等待更新~
容器结构:
WeakMap:{
Object: Map(ObjectKey,Set([]))
}
结构图片
image.png- WeakMap内部 紫色区域
- Map 灰色区域
- ObjectKey 粉色区域
- Set 黄色区域
问题的思考:
为什么用WeakMap?
- WeakMap键名所引用的对象都是弱引用!而且不在JavaScript垃圾回收机制不将其引用考虑在内。就是说,没有引用就自动被清除。
let weak = new WeakMap();
let obj = { a: { a: 1 } };
let otherObj = obj;
let objSubRef = obj.a;
weak.set(obj, "存放");
obj = null;
console.log(weak.get(obj)); // undefined
console.log(weak.get(otherObj)); // 存放
otherObj = null;
console.log(weak.get(otherObj)); // undefined
console.log(objSubRef); // {a:1}
//若在垃圾回收机制中,objSubRef 存在 obj 里的引用,垃圾机制是不回收的。
- WeakMap只接受对象为key,每个数据的引用都是唯一,解决重复key的可能,可以统一存取。
为什么WeakMap的value是用Map来存取?
开发过程中,key不只是String,有可能是symbol等等。详情点击此处
为什么Map的value是用Set来存取?
-
存回调函数,Vue-3.0的 effect API 了解一下。
-
Set的遍历顺序是按照插入顺序来运行。详情点击此处
容器的收集机制
image.pngtrack
export function track(target: object, type: TrackOpTypes, key: unknown) {
if (!shouldTrack || activeEffect === undefined) {
return
}
let depsMap = targetMap.get(target)
if (depsMap === void 0) {
targetMap.set(target, (depsMap = new Map()))
}
let dep = depsMap.get(key)
if (dep === void 0) {
depsMap.set(key, (dep = new Set()))
}
if (!dep.has(activeEffect)) {
dep.add(activeEffect)
activeEffect.deps.push(dep)
if (__DEV__ && activeEffect.options.onTrack) {
activeEffect.options.onTrack({
effect: activeEffect,
target,
type,
key
})
}
}
}
track 主要集中为两个方向服务:
- 容器的初始化与数据收集。
let depsMap = targetMap.get(target)
if (depsMap === void 0) {
targetMap.set(target, (depsMap = new Map()))
}
let dep = depsMap.get(key)
if (dep === void 0) {
depsMap.set(key, (dep = new Set()))
}
- 当前key是否与 effect API 组合使用?若是:把 effect 包裹的函数收集; effect 第二个参数是否有参,且为onTrack,若有,立刻调用。
if (!dep.has(activeEffect)) {
dep.add(activeEffect)
activeEffect.deps.push(dep)
if (__DEV__ && activeEffect.options.onTrack) {
activeEffect.options.onTrack({
effect: activeEffect,
target,
type,
key
})
}
}
trigger
``javascript
export function trigger(
target: object,
type: TriggerOpTypes,
key?: unknown,
extraInfo?: DebuggerEventExtraInfo
) {
const depsMap = targetMap.get(target)
if (depsMap === void 0) {
// never been tracked
return
}
const effects = new Set<ReactiveEffect>()
const computedRunners = new Set<ReactiveEffect>()
if (type === TriggerOpTypes.CLEAR) {
// collection being cleared, trigger all effects for target
depsMap.forEach(dep => {
addRunners(effects, computedRunners, dep)
})
} else {
// schedule runs for SET | ADD | DELETE
if (key !== void 0) {
addRunners(effects, computedRunners, depsMap.get(key))
}
// also run for iteration key on ADD | DELETE
if (type === TriggerOpTypes.ADD || type === TriggerOpTypes.DELETE) {
const iterationKey = isArray(target) ? 'length' : ITERATE_KEY
addRunners(effects, computedRunners, depsMap.get(iterationKey))
}
}
const run = (effect: ReactiveEffect) => {
scheduleRun(effect, target, type, key, extraInfo)
}
// Important: computed effects must be run first so that computed getters
// can be invalidated before any normal effects that depend on them are run.
computedRunners.forEach(run)
effects.forEach(run)
}
主要为目标对应dep容器存储的函数的执行:
1. 筛选computer组、普通函数组。
2. 执行分先后,先computer组,后普通函数组。