Skip to content

依赖追踪

我们如何去理解依赖这个概念呢?

我们定义一个叫Dep类,这个类有两个方法,一个是depend,一个是notifydepend用于收集依赖,即把依赖这个状态的代码(也就是回调函数)保存起来。 notify用于将之前收集到的所有依赖代码,重新执行。

然后我们会定义一个函数autoRun(),这个函数用于接收一个更新函数,当我们执行autoRun()时,会执行传入的更新函数,并保存更新函数,当notify被调用时,会重新执行更新函数。

练习:实现依赖追踪

js
class Dep {
  // TODO:补充完整
}
function autoRun() {
  // TODO:补充完整
}

const dep = new Dep()

autoRun(() => {
  dep.depend()
  console.log('updated!')
})
// 输出日志: "updated!"

dep.notify()  // 输出日志: "updated!"

答案

js
let activeUpdate = null

class Dep {
  constructor() {
    this.subscribers = new Set()
  }
  depend() {
    if(activeUpdate) {
      this.subscribers.add(activeUpdate)
    }
  }
  notify() {
    this.subscribers.forEach(sub => sub())
  }
}
function autoRun(update) {
  function wrapUpdate() {
    activeUpdate = update
    update()
    activeUpdate = null
  }
  wrapUpdate()
}

const dep = new Dep()

autoRun(() => {
  dep.depend()
  console.log('updated!')
})
// 输出日志: "updated!"

dep.notify()  // 输出日志: "updated!"
image-20250614155125145

执行顺序就是:

  1. 实例化Dep
  2. 调用autoRun()
  3. 将传入autoRun()的更新函数update()保存到变量activeUpdate,然后执行更新函数update()
  4. 执行更新函数时,会执行dep.depend()实现依赖保存,然后将activeUpdate重置为空
  5. 接下来开始调用dep.notify(),执行重新执行更新函数
  6. 这次执行更新函数时,虽然也调用了dep.depend(),但由于activeUpdate为空,所以依赖没有重复保存,然后就直接执行了console.log('updated!')

如此我们便成功实现了依赖追踪。