vue中响应式系统Watcher和Dep的双向绑定机制的具体源码体现

47 阅读1分钟

在Vue的响应式系统中,dep.addSub(this)是实现Dep→Watcher关联的关键代码,而组件销毁时的依赖清理则通过Watcher的teardown机制实现,下面主要介绍下两者的联系。

双向绑定的整体实现逻辑

  • Watcher侧‌:通过newDepsnewDepIds记录当前Watcher依赖的所有Dep实例
  • Dep侧‌:通过addSub将Watcher存入subs数组,形成反向引用这种双向记录确保:
  • 数据变更时能精准找到关联Watcher(Dep→Watcher)
  • 组件销毁时可清理无用依赖(Watcher→Dep)

Dep类中的具体源码:

addDep(dep: Dep) { 
const id = dep.id 
if (!this.newDepIds.has(id)) {
    this.newDepIds.add(id) 
    this.newDeps.push(dep) 
    if (!this.depIds.has(id)) { 
        dep.addSub(this) 
       } 
} 
}

一、Dep→Watcher 精准通知机制

  1. dep.addSub(this)的核心作用
    当Watcher在求值过程中访问响应式数据时,会通过dep.depend()触发依赖收集,最终调用watcher.addDep()方法。在该方法中,若发现是新依赖(通过depIds判断),则会执行dep.addSub(this)将当前Watcher实例添加到Dep的subs数组
// Watcher.addDep 方法片段
if (!this.depIds.has(id)) {
  dep.addSub(this) // 建立Dep到Watcher的引用
}

‌2.数据变更时的通知流程
当数据变更触发setter时,会调用dep.notify()遍历subs数组中的所有Watcher,依次执行其update()方法,实现精准更新

二、Watcher→Dep 依赖清理机制

  1. 组件销毁时的清理入口
    组件销毁时会调用Watcher的teardown()方法(或stop()),该方法会遍历Watcher的所有依赖(deps数组),调用dep.removeSub(this)将自身从Dep的订阅列表中移除
teardown() {
  if (this.vm && !this.vm._isBeingDestroyed) {
    remove(this.vm._scope.effects, this)
  }
  if (this.active) {
    let i = this.deps.length
    while (i--) {
      this.deps[i].removeSub(this)//// 从Dep中移除当前Watcher
    }
    this.active = false// 标记为无效状态
    if (this.onStop) {
      this.onStop()
    }
  }
}

这一过程确保:

  • 被销毁组件的Watcher不再接收无用通知
  • Dep的subs数组保持最小化,避免内存泄漏