Vue3 的响应式系统源码级执行流程解析
字数 388 2025-11-06 12:41:12

Vue3 的响应式系统源码级执行流程解析

题目描述:深入分析 Vue3 响应式系统从初始化到触发更新的完整源码级执行流程,包括依赖收集、触发更新等核心环节的具体实现细节。

解题过程

1. 响应式对象创建阶段

// reactive() 函数入口
function reactive(target) {
  return createReactiveObject(target, false, mutableHandlers)
}

function createReactiveObject(target, isReadonly, baseHandlers) {
  // 1. 检查是否已经是响应式对象
  if (target.__v_raw) return target
  
  // 2. 使用 Proxy 创建响应式代理
  const proxy = new Proxy(target, baseHandlers)
  // 3. 建立原始对象与代理对象的映射关系
  reactiveMap.set(target, proxy)
  return proxy
}

2. 依赖收集的核心实现

// mutableHandlers 中的 get 拦截器
const get = createGetter()

function createGetter() {
  return function get(target, key, receiver) {
    // 1. 获取原始值
    const res = Reflect.get(target, key, receiver)
    
    // 2. 执行依赖收集(核心)
    track(target, "get", key)
    
    // 3. 如果值是对象,递归响应化
    if (isObject(res)) {
      return reactive(res)
    }
    
    return res
  }
}

// track 函数实现依赖收集
function track(target, type, key) {
  // 1. 获取当前正在执行的副作用函数
  let activeEffect = effectStack[effectStack.length - 1]
  if (!activeEffect) return
  
  // 2. 获取 target 对应的依赖映射
  let depsMap = targetMap.get(target)
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()))
  }
  
  // 3. 获取 key 对应的依赖集合
  let dep = depsMap.get(key)
  if (!dep) {
    depsMap.set(key, (dep = new Set()))
  }
  
  // 4. 建立双向关联
  if (!dep.has(activeEffect)) {
    dep.add(activeEffect)
    activeEffect.deps.push(dep) // 副作用函数记录自己属于哪些依赖集合
  }
}

3. 副作用函数(effect)注册机制

function effect(fn, options = {}) {
  // 1. 创建副作用函数
  const effect = createReactiveEffect(fn, options)
  
  // 2. 如果不是懒执行,立即执行一次进行初始依赖收集
  if (!options.lazy) {
    effect()
  }
  
  return effect
}

function createReactiveEffect(fn, options) {
  const effect = function reactiveEffect() {
    // 防止递归调用
    if (!effectStack.includes(effect)) {
      try {
        // 1. 压入栈顶,设置为当前活跃的 effect
        effectStack.push(effect)
        activeEffect = effect
        
        // 2. 执行原始函数,触发依赖收集
        return fn()
      } finally {
        // 3. 执行完成,弹出栈
        effectStack.pop()
        activeEffect = effectStack[effectStack.length - 1]
      }
    }
  }
  
  // 记录相关元信息
  effect.deps = [] // 该 effect 所属的所有依赖集合
  effect.options = options
  
  return effect
}

4. 触发更新的完整流程

// set 拦截器实现
const set = createSetter()

function createSetter() {
  return function set(target, key, value, receiver) {
    // 1. 获取旧值,判断操作类型(新增/修改)
    const oldValue = target[key]
    const hadKey = hasOwn(target, key)
    
    // 2. 执行反射设置
    const result = Reflect.set(target, key, value, receiver)
    
    // 3. 触发更新(核心)
    if (!hadKey) {
      trigger(target, "add", key, value)
    } else if (value !== oldValue) {
      trigger(target, "set", key, value, oldValue)
    }
    
    return result
  }
}

// trigger 函数实现更新触发
function trigger(target, type, key, newValue, oldValue) {
  // 1. 获取 target 对应的所有依赖
  const depsMap = targetMap.get(target)
  if (!depsMap) return
  
  // 2. 创建需要执行的 effect 集合(避免重复和递归)
  const effects = new Set()
  const add = (effectsToAdd) => {
    if (effectsToAdd) {
      effectsToAdd.forEach(effect => {
        if (effect !== activeEffect) { // 避免当前正在执行的 effect
          effects.add(effect)
        }
      })
    }
  }
  
  // 3. 根据操作类型收集相关依赖
  if (key !== void 0) {
    add(depsMap.get(key)) // 该 key 对应的依赖
  }
  
  // 4. 数组特殊处理
  if (type === 'add' && isArray(target)) {
    add(depsMap.get('length')) // 数组新增影响 length
  }
  
  // 5. 执行所有收集到的 effect
  const run = (effect) => {
    if (effect.options.scheduler) {
      effect.options.scheduler(effect) // 使用调度器
    } else {
      effect() // 直接执行
    }
  }
  
  effects.forEach(run)
}

5. 调度器(scheduler)与批量更新

// Vue 组件更新使用的调度器
const scheduler = (effect) => {
  // 1. 将 effect 加入队列,准备批量更新
  if (!queue.includes(effect)) {
    queue.push(effect)
    
    // 2. 使用微任务延迟执行,实现批量更新
    if (!isFlushing) {
      nextTick(flushJobs)
    }
  }
}

function flushJobs() {
  isFlushing = true
  
  // 排序保证:父组件在子组件之前更新
  queue.sort((a, b) => a.id - b.id)
  
  // 批量执行所有 effect
  for (let i = 0; i < queue.length; i++) {
    const effect = queue[i]
    effect()
  }
  
  // 清空队列
  queue.length = 0
  isFlushing = false
}

关键执行流程总结

  1. 初始化阶段:Proxy 拦截器设置,建立响应式对象
  2. 依赖收集阶段:effect 执行时通过 getter 建立 target→key→effect 的映射关系
  3. 更新触发阶段:setter 通过映射关系找到对应 effect,通过调度器批量执行
  4. 清理阶段:effect 重新执行前清理旧依赖,避免无效更新

这个流程确保了 Vue3 响应式系统的高效性和精确性,是 Vue 组件更新的核心基础。

Vue3 的响应式系统源码级执行流程解析 题目描述 :深入分析 Vue3 响应式系统从初始化到触发更新的完整源码级执行流程,包括依赖收集、触发更新等核心环节的具体实现细节。 解题过程 : 1. 响应式对象创建阶段 2. 依赖收集的核心实现 3. 副作用函数(effect)注册机制 4. 触发更新的完整流程 5. 调度器(scheduler)与批量更新 关键执行流程总结 : 初始化阶段 :Proxy 拦截器设置,建立响应式对象 依赖收集阶段 :effect 执行时通过 getter 建立 target→key→effect 的映射关系 更新触发阶段 :setter 通过映射关系找到对应 effect,通过调度器批量执行 清理阶段 :effect 重新执行前清理旧依赖,避免无效更新 这个流程确保了 Vue3 响应式系统的高效性和精确性,是 Vue 组件更新的核心基础。