const effectStack = []const targetMap = new WeakMap()
接下来定义这收集依赖及触发依赖更新这两个函数:
function track(target, key) {
// 从栈中拿到待收集的依赖对象
let effect = effectStack[effectStack.length - 1] if (effect) {
// 通过 target 及 key 从依赖映射表中拿到对应的依赖列表(Set类型)
// 首次需要对依赖映射表初始化
let depsMap = targetMap.get(target)
if (depsMap === undefined) {
depsMap = new Map()
targetMap.set(target, depsMap)
}
let dep = depsMap.get(key)
if (dep === undefined) {
dep = new Set()
depsMap.set(key, dep)
}
// 若 target.key 对应的依赖列表中不存在该依赖则收集
if (!dep.has(effect)) {
dep.add(effect)
}
}
}
function trigger(target, key, info) {
// 依赖映射表中取出 target 相关数据
const depsMap = targetMap.get(target)
if (depsMap === undefined) {
return
}
// 普通依赖对象的列表
const effects = new Set()
// 计算属性依赖对象的列表
const computedRunners = new Set()
if (key) {
// 取出 key 相关的依赖列表遍历分类存入 effects 及 computedRunners
let deps = depsMap.get(key)
deps.forEach(effect => {
if (effect.computed) {
computedRunners.add(effect)
} else {
effects.add(effect)
}
})
}
// 遍历执行所有依赖对象
const run = effect=> effect()
effects.forEach(run)
computedRunners.forEach(run)
}
track 及 trigger 的大致代码也很简单,track 是拿到待收集的依赖对象 effect 后收集到 effectStack,trigger 是从 effectStack 拿到对应的依赖列表遍历执行。
到现在就差这个依赖对象了,根据上面 trigger 函数可以知道,这个依赖 effect 首先是个函数可以执行,并且还有自身属性,如 computed 表示其为一个计算属性的依赖,有时会根据该标识进行写特殊处理。
下面开始介绍这个依赖对象是如何产生的:
// 创建依赖对象
function createReactiveEffect(fn, options) {
const effect = function effect(...args) {
return run(effect, fn, args)
}
effect.computed = options.computed
effect.lazy = options.lazy
return effect
}function run(effect, fn, args) {
if (!effectStack.includes(effect)) {
try {
effectStack.push(effect)
return fn(...args)
} finally {
effectStack.pop()
}
}
}
createReactiveEffect 是一个高阶函数,内部创建了一个名为 effect 的函数,函数内部返回的是一个 run 函数,run 函数中将依赖 effect 对象存入全局的待收集依赖栈 effectStack 中,并执行传入的回调函数,该回调函数其实就是一开始示例中 effect 函数传入的修改 Dom 的函数。也就是说依赖对象作为函数直接执行就会添加依赖到全局栈并执行回调函数。










