Skip to content

响应式原理

reactive 这个函数有什么用

reactive 接收一个对象,并返回一个代理对象。在effect中对代理对象进行取值操作时,会对该属性进行依赖收集,并在该属性重新赋值的时候触发依赖, 即重新运行所有依赖该属性的effect

effect 这个函数有什么用

effect 接收一个函数和一个选项并返回一个runnereffect 会立即执行该函数,如果该函数中对响应式对象取值操作,则会对该属性进行依赖收集,并在该属性变化(赋值)的时候重新运行该函数。

对于返回的runner 可以调用它来执行传入的函数 在选项中可以传入调度函数(scheduler)来覆盖effect默认的调度函数, 通过传入调度函数与返回的runner做配合, 可以在函数重新执行前做额外的操作,实现切面编程的效果

ts
const runner = effect(() => {}, { scheduler: () => {
  // 额外的操作
  runner()
} })

依赖收集 & 依赖触发 & 依赖清理

依赖收集

reactive 返回的的是一个代理对象 ,对reactive取值时,会触发get 操作,如果取值操作是在effect中,会进行依赖收集

有一个全局的依赖表targetMap 会记录所有的属性和effect的依赖关系,targetMap的数据结构形如

ts
{
  {name: "zx", age: 18}: {
    name: {
      effect1,
      effect2
    },
    age: {
      effect1
    }
  }
}

初次收集时, track方法会创建一个类似上述结构的依赖关系 并将当前触发该收集的effect存入依赖关系, 并且在effect实例中会维护一个deps数组存储effect对应的依赖, 如果effect重新运行, 会触发重新收集依赖 此时会有一个简单的diff算法, 如果收集的依赖相同会则复用, 如果不同则触发依赖清理并添加新的依赖项.

依赖清理

effect 执行前会先进行依赖预清理, 在effect执行后会进行依赖后清理 在依赖收集过程中如果当前收集的依赖和上一次收集的依赖不相同,会触发依赖清理并添加新的依赖项

依赖预清理 将effect内的维护的依赖长度清零, 等待diff

依赖后清理 查看依赖数组的长度和维护依赖长度, 如果数组长度大于维护依赖长度, 则清理多出的依赖

依赖触发

对被依赖收过的响应式对象进行赋值操作时,如果新旧值不相等,会依赖触发. 依赖触发时,在targetMap取出依赖对应的所有effect, 依次触发effect