Vue3 Reactive System Source Code Level Execution Flow Analysis

Vue3 Reactive System Source Code Level Execution Flow Analysis

Problem Description: Deeply analyze the complete source code level execution flow of Vue3's reactive system, from initialization to update triggering, including specific implementation details of core stages like dependency collection and update triggering.

Solution Process:

1. Reactive Object Creation Stage

// reactive() function entry
function reactive(target) {
  return createReactiveObject(target, false, mutableHandlers)
}

function createReactiveObject(target, isReadonly, baseHandlers) {
  // 1. Check if already a reactive object
  if (target.__v_raw) return target
  
  // 2. Create reactive proxy using Proxy
  const proxy = new Proxy(target, baseHandlers)
  // 3. Establish mapping between raw object and proxy object
  reactiveMap.set(target, proxy)
  return proxy
}

2. Core Implementation of Dependency Collection

// get interceptor in mutableHandlers
const get = createGetter()

function createGetter() {
  return function get(target, key, receiver) {
    // 1. Get raw value
    const res = Reflect.get(target, key, receiver)
    
    // 2. Perform dependency collection (core)
    track(target, "get", key)
    
    // 3. If value is an object, recursively make it reactive
    if (isObject(res)) {
      return reactive(res)
    }
    
    return res
  }
}

// track function implements dependency collection
function track(target, type, key) {
  // 1. Get the currently executing side effect function
  let activeEffect = effectStack[effectStack.length - 1]
  if (!activeEffect) return
  
  // 2. Get the dependency map for the target
  let depsMap = targetMap.get(target)
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()))
  }
  
  // 3. Get the dependency set for the key
  let dep = depsMap.get(key)
  if (!dep) {
    depsMap.set(key, (dep = new Set()))
  }
  
  // 4. Establish bidirectional association
  if (!dep.has(activeEffect)) {
    dep.add(activeEffect)
    activeEffect.deps.push(dep) // Side effect function records which dependency sets it belongs to
  }
}

3. Side Effect Function (effect) Registration Mechanism

function effect(fn, options = {}) {
  // 1. Create side effect function
  const effect = createReactiveEffect(fn, options)
  
  // 2. If not lazy execution, execute immediately for initial dependency collection
  if (!options.lazy) {
    effect()
  }
  
  return effect
}

function createReactiveEffect(fn, options) {
  const effect = function reactiveEffect() {
    // Prevent recursive calls
    if (!effectStack.includes(effect)) {
      try {
        // 1. Push to top of stack, set as currently active effect
        effectStack.push(effect)
        activeEffect = effect
        
        // 2. Execute original function, trigger dependency collection
        return fn()
      } finally {
        // 3. After execution, pop from stack
        effectStack.pop()
        activeEffect = effectStack[effectStack.length - 1]
      }
    }
  }
  
  // Record related metadata
  effect.deps = [] // All dependency sets this effect belongs to
  effect.options = options
  
  return effect
}

4. Complete Flow of Triggering Updates

// set interceptor implementation
const set = createSetter()

function createSetter() {
  return function set(target, key, value, receiver) {
    // 1. Get old value, determine operation type (add/update)
    const oldValue = target[key]
    const hadKey = hasOwn(target, key)
    
    // 2. Perform reflection set
    const result = Reflect.set(target, key, value, receiver)
    
    // 3. Trigger update (core)
    if (!hadKey) {
      trigger(target, "add", key, value)
    } else if (value !== oldValue) {
      trigger(target, "set", key, value, oldValue)
    }
    
    return result
  }
}

// trigger function implements update triggering
function trigger(target, type, key, newValue, oldValue) {
  // 1. Get all dependencies for the target
  const depsMap = targetMap.get(target)
  if (!depsMap) return
  
  // 2. Create set of effects to execute (avoid duplicates and recursion)
  const effects = new Set()
  const add = (effectsToAdd) => {
    if (effectsToAdd) {
      effectsToAdd.forEach(effect => {
        if (effect !== activeEffect) { // Avoid currently executing effect
          effects.add(effect)
        }
      })
    }
  }
  
  // 3. Collect relevant dependencies based on operation type
  if (key !== void 0) {
    add(depsMap.get(key)) // Dependencies for this key
  }
  
  // 4. Special handling for arrays
  if (type === 'add' && isArray(target)) {
    add(depsMap.get('length')) // Array addition affects length
  }
  
  // 5. Execute all collected effects
  const run = (effect) => {
    if (effect.options.scheduler) {
      effect.options.scheduler(effect) // Use scheduler
    } else {
      effect() // Execute directly
    }
  }
  
  effects.forEach(run)
}

5. Scheduler and Batch Updates

// Scheduler used for Vue component updates
const scheduler = (effect) => {
  // 1. Add effect to queue for batch update preparation
  if (!queue.includes(effect)) {
    queue.push(effect)
    
    // 2. Use microtask to delay execution, achieving batch updates
    if (!isFlushing) {
      nextTick(flushJobs)
    }
  }
}

function flushJobs() {
  isFlushing = true
  
  // Sort to ensure: parent components update before child components
  queue.sort((a, b) => a.id - b.id)
  
  // Batch execute all effects
  for (let i = 0; i < queue.length; i++) {
    const effect = queue[i]
    effect()
  }
  
  // Clear queue
  queue.length = 0
  isFlushing = false
}

Key Execution Flow Summary:

  1. Initialization Stage: Proxy interceptor setup, creation of reactive objects.
  2. Dependency Collection Stage: During effect execution, establish target→key→effect mapping via getter.
  3. Update Triggering Stage: Setter finds corresponding effects via mapping and executes them in batches via scheduler.
  4. Cleanup Stage: Clean up old dependencies before effect re-execution to avoid invalid updates.

This flow ensures the efficiency and precision of Vue3's reactive system, forming the core foundation of Vue component updates.