onTrigger?: (event: DebuggerEvent) => void
onStop?: () => void
}
targetMap 类似 {target -> key -> dep}的一个Map结构,用于缓存所有响应式对象和依赖收集。
export type Dep = Set<ReactiveEffect>
export type KeyToDepMap = Map<string | symbol, Dep>
export const targetMap: WeakMap<any, KeyToDepMap> = new WeakMap()
Proxy代理拦截
reactive函数执行,会将传入的target对象通过Proxy包装,拦截它的get,set等,并将代理的target缓存到targetMap,targetMap.set(target, new Map())。
代理的get的时候会调用一个track函数,而set会调用一个triger函数。分别对应依赖收集和触发更新。
// Proxy get 简化
function get(target: any, key: string | symbol, receiver: any) {
// 通过key拿到原始值res
const res = Reflect.get(target, key, receiver)
// 过滤不需要代理的情况
// ...
// 依赖收集
track(target, OperationTypes.GET, key)
// 如果取到的值是个对象,将对象再代理包装一下
// Proxy只能代理对象第一层级
return isObject(res) ? reactive(res) : res
}// Proxy set 简化
function set(
target: any,
key: string | symbol,
value: any,
receiver: any
): boolean {
// 一些不需要代理设置的场景
// ...
// 设置原始对象的值
const result = Reflect.set(target, key, value, receiver)
// 避免重复trigger的逻辑
// ...
// 触发通知更新
trigger(target, '更新的类型, 新增key或更新key', key)
return result
}
依赖收集和触发更新
组件在render阶段,视图会读取数据对象上的值进行渲染,此时便触发了Proxy的get,由此触发对应的track函数,记录下了对应的ReactiveEffect,也就是常说的依赖收集。
ReactiveEffect其实就可以看作是组件的更新(mount是特殊的update),数据的变更触发trigger,trigger遍历调用track收集的对应的数据的ReactiveEffect,也就是对应有关联的组件的更新。
trigger触发的组件的更新,在render阶段又触发了新一轮的track依赖收集,更新依赖。
// 简化的 track
function track(
target: any,
type: OperationTypes,
key?: string | symbol
) {
// 只有在依赖收集阶段才进行依赖收集
// 除了render,其他场景也可能会触发Proxy的get,但不需要进行依赖收集
// activeReactiveEffectStack栈顶包装了当前render的组件的mount和update的逻辑
const effect = activeReactiveEffectStack[activeReactiveEffectStack.length - 1] // 如果effect为空,说明当前不在render阶段
if (effect) {










