trigger主要工作过程是把依赖提取出来,然后一个个执行,下面简述其过程。
export function trigger(
target: object,
type: TriggerOpTypes,
key?: unknown,
newValue?: unknown,
oldValue?: unknown,
oldTarget?: Map<unknown, unknown> | Set<unknown>
) {
// 条件1
const depsMap = targetMap.get(target)
if (!depsMap) {
// never been tracked
return
}
// 条件2
let deps: (Dep | undefined)[] = []
// ①
if (type === TriggerOpTypes.CLEAR) {
// collection being cleared
// trigger all effects for target
deps = [...depsMap.values()]
// ②
} else if (key === 'length' && isArray(target)) {
const newLength = Number(newValue)
depsMap.forEach((dep, key) => {
if (key === 'length' || key >= newLength) {
deps.push(dep)
}
})
// ③
} else {
// schedule runs for SET | ADD | DELETE
if (key !== void 0) {
deps.push(depsMap.get(key))
}
// also run for iteration key on ADD | DELETE | Map.SET
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
}
}
// 条件3
const eventInfo = __DEV__
? { target, type, key, newValue, oldValue, oldTarget }
: undefined
// a
if (deps.length === 1) {
if (deps[0]) {
if (__DEV__) {
triggerEffects(deps[0], eventInfo)
} else {
triggerEffects(deps[0])
}
}
// b
} else {
const effects: ReactiveEffect[] = []
for (const dep of deps) {
if (dep) {
effects.push(...dep)
}
}
if (__DEV__) {
triggerEffects(createDep(effects), eventInfo)
} else {
triggerEffects(createDep(effects))
}
}
}
1.获取依赖映射targetMap中当前(要触发依赖执行的对象target)的映射,如果映射不存在则直接返回
2.设置依赖数组deps,根据依赖触发类型,来收集依赖。
①如果依赖的触发类型type是clear,则把当前对象所有属性方法的依赖全部丢到deps数组中
②如果触发依赖对象是数组,且触发类型是length。deps收集关于length的依赖以及index大于新值的所有依赖
③其他情况。如果非长度为0的属性和方法,直接收集对应方法的依赖。
在触发类型type是add的情况下,如果对象不是数组,则deps收集对象target依赖映射targetMap中关于ITERATE_KEY的依赖,如果对象target是map类型,则deps收集对象target依赖映射targetMap中关于MAP_KEY_ITERATE_KEY的依赖。
在触发类型是delete的情况下,操作跟add的一样。
在触发类型是set的情况下,如果对象target是map类型,则deps收集对象target依赖映射targetMap中关于ITERATE_KEY的依赖。
3.根据依赖数组deps的长度,来分别触发依赖。
a.如果deps的长度为1且有效,通过triggerEffects触发依赖执行
b.其他情况,过滤获取有效依赖,然后由createDep包裹依赖再通过triggerEffects触发依赖执行
triggerEffects函数主要是获取每项依赖,然后调用triggerEffect方法来执行每项依赖,triggerEffects方法体如下
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)
}
}
}
triggerEffect函数简述如下
1.必须满足传入的副作用函数(依赖)不是当前副作用函数,或者副作用函数可被执行才能进行触发依赖
2.满足1条件下,如果副作用存在调度方法,则执行调度方法,否则执行该副作用函数
function triggerEffect(
effect: ReactiveEffect,
debuggerEventExtraInfo?: DebuggerEventExtraInfo
) {
// 条件1
if (effect !== activeEffect || effect.allowRecurse) {
if (__DEV__ && effect.onTrigger) {
effect.onTrigger(extend({ effect }, debuggerEventExtraInfo))
}
// 条件2
if (effect.scheduler) {
effect.scheduler()
} else {
effect.run()
}
}
}
现在派发阶段已经知道,那副作用函数effect长哪样呢?我们下文继续!
本人菜鸡,有问题望前辈及时指出,不胜感激!!