全部学科
Python全栈
python
NodeJS全栈
nodejs
📅 2026-05-20 7 分钟 ✍️ juanwangdev

依赖收集与触发

响应式系统的核心机制是依赖收集(track)与依赖触发(trigger),实现数据与视图的绑定。

Dep 与 Watcher

JavaScript
let uid = 0

class Dep {
  constructor() {
    this.id = uid++
    this.subs = []
  }
  addSub(sub) {
    this.subs.push(sub)
  }
  depend() {
    if (Dep.target) this.addSub(Dep.target)
  }
  notify() {
    this.subs.slice().forEach(sub => sub.update())
  }
}

Dep.target = null

依赖收集过程

数据被读取时触发 getter,收集当前活跃的 Watcher:

JavaScript
function defineReactive(obj, key, val) {
  const dep = new Dep()
  Object.defineProperty(obj, key, {
    get() {
      // 组件渲染时,全局 Dep.target 指向当前 Watcher
      if (Dep.target) {
        dep.depend() // 收集依赖
      }
      return val
    },
    set(newVal) {
      val = newVal
      dep.notify() // 触发更新
    }
  })
}

Watcher 类

JavaScript
class Watcher {
  constructor(vm, expOrFn, cb) {
    this.vm = vm
    this.cb = cb
    this.getter = typeof expOrFn === 'function' ? expOrFn : () => vm[expOrFn]
    this.value = this.get()
  }
  get() {
    Dep.target = this
    const value = this.getter.call(this.vm)
    Dep.target = null
    return value
  }
  update() {
    const oldValue = this.value
    this.value = this.get()
    this.cb.call(this.vm, this.value, oldValue)
  }
}

Vue 3 的 track 与 trigger

Vue 3 使用 WeakMap + Map + Set 存储依赖关系:

JavaScript
const targetMap = new WeakMap()

function track(target, key) {
  if (!Dep.target) return
  let depsMap = targetMap.get(target)
  if (!depsMap) targetMap.set(target, (depsMap = new Map()))
  let dep = depsMap.get(key)
  if (!dep) depsMap.set(key, (dep = new Set()))
  dep.add(Dep.target)
}

function trigger(target, key) {
  const depsMap = targetMap.get(target)
  if (!depsMap) return
  const dep = depsMap.get(key)
  if (dep) dep.forEach(effect => effect())
}

计算属性的依赖缓存

JavaScript
const fullName = computed(() => `${firstName.value} ${lastName.value}`)
// firstName 和 lastName 的 getter 执行时收集了 computed 作为依赖
// 只有两者之一变化时,fullName 才会重新计算

要点总结

  • getter 中调用 dep.depend() 收集当前 Watcher
  • setter 中调用 dep.notify() 通知所有 Watcher 更新
  • Vue 2 使用 Dep + Watcher 类实现
  • Vue 3 使用 WeakMap 存储依赖关系,更高效的 track/trigger
想在手机上练习这篇文章的配套题目?
使用微信卷王开发者小程序,打开首页顶部扫码功能识别二维码
← 上一篇 响应式原理
下一篇 → 虚拟DOM与Diff算法
扫码体验小程序
加载中
想在手机上刷题学习?
使用微信卷王开发者小程序,打开首页顶部扫码功能识别二维码