Skip to content

源码分析-响应式原理

1. 响应式系统基础

1.1 核心概念

Vue的响应式系统主要由以下几个部分组成:

  • Observer:数据劫持,负责将数据对象的属性转换为getter/setter
  • Dep:依赖收集器,用于存储和通知Watcher
  • Watcher:观察者,负责监听数据变化并触发回调

1.2 基本原理

js
// Vue2.x响应式实现核心代码
function defineReactive(obj, key, val) {
  // 为每个属性创建一个Dep实例
  const dep = new Dep()
  
  Object.defineProperty(obj, key, {
    get() {
      // 依赖收集
      if (Dep.target) {
        dep.depend()
      }
      return val
    },
    set(newVal) {
      if (val === newVal) return
      val = newVal
      // 通知更新
      dep.notify()
    }
  })
}

2. Observer实现

2.1 对象的响应式处理

js
class Observer {
  constructor(value) {
    this.value = value
    this.dep = new Dep()
    
    def(value, '__ob__', this)
    
    if (Array.isArray(value)) {
      // 数组响应式处理
      this.observeArray(value)
    } else {
      // 对象响应式处理
      this.walk(value)
    }
  }
  
  walk(obj) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      defineReactive(obj, keys[i], obj[keys[i]])
    }
  }
  
  observeArray(items) {
    for (let i = 0; i < items.length; i++) {
      observe(items[i])
    }
  }
}

2.2 数组方法的拦截

js
const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto)

;['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(method => {
  const original = arrayProto[method]
  def(arrayMethods, method, function mutator(...args) {
    const result = original.apply(this, args)
    const ob = this.__ob__
    let inserted
    
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
    }
    
    if (inserted) ob.observeArray(inserted)
    ob.dep.notify()
    return result
  })
})

3. 依赖收集

3.1 Dep实现

js
class Dep {
  constructor() {
    this.subs = []
  }
  
  addSub(sub) {
    this.subs.push(sub)
  }
  
  removeSub(sub) {
    remove(this.subs, sub)
  }
  
  depend() {
    if (Dep.target) {
      Dep.target.addDep(this)
    }
  }
  
  notify() {
    const subs = this.subs.slice()
    for (let i = 0; i < subs.length; i++) {
      subs[i].update()
    }
  }
}

// 当前正在评估的Watcher
Dep.target = null
const targetStack = []

3.2 依赖收集过程

js
function pushTarget(watcher) {
  if (Dep.target) targetStack.push(Dep.target)
  Dep.target = watcher
}

function popTarget() {
  Dep.target = targetStack.pop()
}

4. Watcher实现

4.1 基本结构

js
class Watcher {
  constructor(vm, expOrFn, cb, options) {
    this.vm = vm
    this.cb = cb
    this.deps = []
    this.newDeps = []
    this.depIds = new Set()
    this.newDepIds = new Set()
    
    if (typeof expOrFn === 'function') {
      this.getter = expOrFn
    } else {
      this.getter = parsePath(expOrFn)
    }
    
    this.value = this.get()
  }
  
  get() {
    pushTarget(this)
    let value
    try {
      value = this.getter.call(this.vm, this.vm)
    } finally {
      popTarget()
      this.cleanupDeps()
    }
    return value
  }
}

4.2 更新机制

js
update() {
  if (this.lazy) {
    this.dirty = true
  } else if (this.sync) {
    this.run()
  } else {
    queueWatcher(this)
  }
}

run() {
  const value = this.get()
  const oldValue = this.value
  this.value = value
  
  if (this.user) {
    try {
      this.cb.call(this.vm, value, oldValue)
    } catch (e) {
      handleError(e, this.vm, `callback for watcher "${this.expression}"`)
    }
  } else {
    this.cb.call(this.vm, value, oldValue)
  }
}

5. Vue3的响应式系统

5.1 Proxy实现

js
function reactive(target) {
  const handler = {
    get(target, key, receiver) {
      const result = Reflect.get(target, key, receiver)
      track(target, key)
      return result
    },
    set(target, key, value, receiver) {
      const oldValue = target[key]
      const result = Reflect.set(target, key, value, receiver)
      if (oldValue !== value) {
        trigger(target, key)
      }
      return result
    }
  }
  
  return new Proxy(target, handler)
}

5.2 依赖追踪

js
const targetMap = new WeakMap()

function track(target, key) {
  if (!activeEffect) 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(activeEffect)
}

6. 性能优化

6.1 批量更新

js
const queue = []
let flushing = false
let waiting = false

function queueWatcher(watcher) {
  if (!queue.includes(watcher)) {
    queue.push(watcher)
    if (!waiting) {
      waiting = true
      nextTick(flushSchedulerQueue)
    }
  }
}

6.2 深度监听优化

js
function observe(value, asRootData) {
  if (!isObject(value)) return
  let ob
  if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
    ob = value.__ob__
  } else if (
    (Array.isArray(value) || isPlainObject(value)) &&
    Object.isExtensible(value)
  ) {
    ob = new Observer(value)
  }
  return ob
}

7. 常见问题处理

7.1 数组变更检测

js
// 重写数组方法
const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]

methodsToPatch.forEach(method => {
  const original = arrayProto[method]
  def(arrayMethods, method, function (...args) {
    const result = original.apply(this, args)
    const ob = this.__ob__
    ob.dep.notify()
    return result
  })
})

7.2 对象新属性处理

js
function set(target, key, val) {
  if (Array.isArray(target) && isValidArrayIndex(key)) {
    target.length = Math.max(target.length, key)
    target.splice(key, 1, val)
    return val
  }
  
  if (key in target && !(key in Object.prototype)) {
    target[key] = val
    return val
  }
  
  const ob = target.__ob__
  if (!ob) {
    target[key] = val
    return val
  }
  
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}

8. 注意事项

  1. 避免大量深层次的响应式数据
  2. 合理使用Object.freeze()
  3. 注意数组变异方法的限制
  4. 理解Vue3的响应式差异
  5. 性能优化的时机选择