响应式原理
reactive 这个函数有什么用
reactive
接收一个对象,并返回一个代理对象。在effect中对代理对象进行取值操作时,会对该属性进行依赖收集,并在该属性重新赋值的时候触发依赖, 即重新运行所有依赖该属性的effect
effect 这个函数有什么用
effect
接收一个函数和一个选项并返回一个runner
,effect
会立即执行该函数,如果该函数中对响应式对象有取值操作,则会对该属性进行依赖收集,并在该属性变化(赋值)的时候重新运行该函数。
对于返回的runner
可以调用它来执行传入的函数 在选项中可以传入调度函数(scheduler)来覆盖effect默认的调度函数, 通过传入调度函数与返回的runner
做配合, 可以在函数重新执行前做额外的操作,实现切面编程的效果
const runner = effect(() => {}, { scheduler: () => {
// 额外的操作
runner()
} })
依赖收集 & 依赖触发 & 依赖清理
依赖收集
reactive
返回的的是一个代理对象 ,对reactive
取值时,会触发get
操作,如果取值操作是在effect
中,会进行依赖收集
有一个全局的依赖表targetMap
会记录所有的属性和effect
的依赖关系,targetMap
的数据结构形如
{
{name: "zx", age: 18}: {
name: {
effect1,
effect2
},
age: {
effect1
}
}
}
初次收集时, track
方法会创建一个类似上述结构的依赖关系 并将当前触发该收集的effect
存入依赖关系, 并且在effect
实例中会维护一个deps
数组存储effect对应的依赖, 如果effect
重新运行, 会触发重新收集依赖
此时会有一个简单的diff算法, 如果收集的依赖相同会则复用, 如果不同则触发依赖清理并添加新的依赖项.
依赖清理
effect
执行前会先进行依赖预清理, 在effect
执行后会进行依赖后清理 在依赖收集过程中如果当前收集的依赖和上一次收集的依赖不相同,会触发依赖清理并添加新的依赖项
依赖预清理 将effect
内的维护的依赖长度清零, 等待diff
依赖后清理 查看依赖数组的长度和维护依赖长度, 如果数组长度大于维护依赖长度, 则清理多出的依赖
依赖触发
对被依赖收过的响应式对象进行赋值操作时,如果新旧值不相等,会依赖触发. 依赖触发时,在targetMap
取出依赖对应的所有effect
, 依次触发effect