美文网首页
Vue 3.0 - track与trigger的容器

Vue 3.0 - track与trigger的容器

作者: CodeYJ | 来源:发表于2020-06-23 20:24 被阅读0次

前言

此文章为早期版本,可能与当前最新版本有出入,敬请等待更新~

容器结构:

WeakMap:{
  Object: Map(ObjectKey,Set([]))
}

结构图片

image.png
  • WeakMap内部 紫色区域
  • Map 灰色区域
  • ObjectKey 粉色区域
  • Set 黄色区域

问题的思考:

为什么用WeakMap?

  1. 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 里的引用,垃圾机制是不回收的。
  1. WeakMap只接受对象为key,每个数据的引用都是唯一,解决重复key的可能,可以统一存取。

为什么WeakMap的value是用Map来存取?

开发过程中,key不只是String,有可能是symbol等等。详情点击此处

为什么Map的value是用Set来存取?

  1. 存回调函数,Vue-3.0的 effect API 了解一下。

  2. Set的遍历顺序是按照插入顺序来运行。详情点击此处

容器的收集机制

image.png

track

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 主要集中为两个方向服务:

  1. 容器的初始化与数据收集。
 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()))
  }
  1. 当前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组,后普通函数组。

相关文章

网友评论

      本文标题:Vue 3.0 - track与trigger的容器

      本文链接:https://www.haomeiwen.com/subject/jwqkfktx.html