总结来说: vue使用模块全局变量来进行依赖收集
极简版的vue3 依赖收集源码
function ref(value) {
return createRef(value)
}
function createRef(value) {
return new RefImpl(value)
}
class RefImpl {
constructor(value) {
this._value = value
}
get value() {
track(this, 'value')
return this._value
}
set value(newVal) {
this._value = newVal
trigger(this, 'value')
}
}
const targetMap = new WeakMap()
let activeEffect
function track(target, key) {
let depMap = targetMap.get(target)
if (!depMap) {
targetMap.set(target, (depMap = new Map()))
}
let deps = depMap.get(key)
if (!deps) {
depMap.set(key, deps = new Set())
}
if(activeEffect) {
deps.add(activeEffect)
activeEffect.deps.push(deps)
}
}
function effect(fn) {
const effect1 = createReactiveEffect(fn)
effect1()
}
function createReactiveEffect(fn) {
const effect = function reactiveEffect() {
activeEffect = effect
return fn()
}
effect.deps = []
return effect
}
function trigger(target, key) {
const depMap = targetMap.get(target)
if (!depMap) return
const deps = depMap.get(key)
deps.forEach(dep => {
dep()
})
}
- 对外暴漏两个api, ref 和effect
- ref用于创建一个基本值的包装对象RefImpl的实例
- RefImpl的getter中会触发依赖收集
- RefImpl的getter中会触发包装对象,也就是值的订阅者
- effec会创建一个effect的函数, 并且立即执行一次,把全局变量activeEffect设置为本身, 并在effect中执行订阅函数
- 订阅函数会立即触发ref的getter, 从而触发track,把当前的effect加入订阅者列表里
- 当ref实例的value改变时, 会触发trigger,从而触发订阅者
github链接
|