阿里云主机折上折
  • 微信号
Current Site:Index > The core idea of a responsive system

The core idea of a responsive system

Author:Chuan Chen 阅读数:10479人阅读 分类: Vue.js

Core Concepts of Reactive Systems

Reactive systems are one of the core mechanisms in modern frontend frameworks, capable of automatically tracking data changes and updating related views. Vue 3's reactive system is based on Proxy, offering significant improvements over Vue 2's Object.defineProperty.

Data Hijacking and Dependency Collection

Vue 3 uses Proxy to intercept object operations, collecting dependencies in getters and triggering updates in setters. This mechanism is more efficient than Vue 2's recursive traversal of object properties.

const reactiveMap = new WeakMap()

function reactive(target) {
  const proxy = new Proxy(target, {
    get(target, key, receiver) {
      track(target, key) // Collect dependencies
      return Reflect.get(target, key, receiver)
    },
    set(target, key, value, receiver) {
      const oldValue = target[key]
      const result = Reflect.set(target, key, value, receiver)
      if (oldValue !== value) {
        trigger(target, key) // Trigger updates
      }
      return result
    }
  })
  reactiveMap.set(target, proxy)
  return proxy
}

Implementation of Dependency Tracking

Each reactive property is associated with a dependency collection (Dep). When a property is accessed, the currently running effect (side effect) is recorded in the dependency collection.

let activeEffect = null
const targetMap = new WeakMap()

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

The Update Triggering Process

When reactive data changes, the system looks up the corresponding dependency collection and executes all the side effect functions within it.

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

Side Effect Management

Side effects (effects) are the core concept of reactive systems, representing code that responds to data changes. Vue 3 creates and manages side effects through the effect function.

function effect(fn) {
  const effectFn = () => {
    cleanup(effectFn)
    activeEffect = effectFn
    fn()
    activeEffect = null
  }
  effectFn.deps = []
  effectFn()
}

function cleanup(effectFn) {
  for (const dep of effectFn.deps) {
    dep.delete(effectFn)
  }
  effectFn.deps.length = 0
}

Implementation Differences in Reactive APIs

Vue 3 provides multiple ways to create reactive data, each with different characteristics and use cases.

Differences Between ref and reactive

function ref(value) {
  const refObj = {
    get value() {
      track(refObj, 'value')
      return value
    },
    set value(newVal) {
      if (newVal !== value) {
        value = newVal
        trigger(refObj, 'value')
      }
    }
  }
  return refObj
}

Implementation of shallowReactive

Shallow reactive objects only make top-level properties reactive:

function shallowReactive(target) {
  return new Proxy(target, {
    get(target, key, receiver) {
      if (key === '__v_isReactive') return true
      const res = Reflect.get(target, key, receiver)
      track(target, key)
      return res
    },
    // setter is the same as reactive
  })
}

Optimization Strategies in the Reactive System

Vue 3's reactive system includes multiple performance optimizations to ensure efficiency in complex scenarios.

Optimization of Dependency Collection

Bitwise operations are used to mark dependency relationships, reducing unnecessary dependency collection:

const enum TrackOpTypes {
  GET = 'get',
  HAS = 'has',
  ITERATE = 'iterate'
}

const enum TriggerOpTypes {
  SET = 'set',
  ADD = 'add',
  DELETE = 'delete',
  CLEAR = 'clear'
}

Batch Update Mechanism

Microtask queues are used to batch process updates, avoiding redundant rendering:

const queue = []
let isFlushing = false

function queueJob(job) {
  if (!queue.includes(job)) {
    queue.push(job)
    if (!isFlushing) {
      isFlushing = true
      Promise.resolve().then(flushJobs)
    }
  }
}

function flushJobs() {
  try {
    for (let i = 0; i < queue.length; i++) {
      queue[i]()
    }
  } finally {
    queue.length = 0
    isFlushing = false
  }
}

Reactive System and Component Rendering

Changes in reactive data ultimately trigger component re-rendering, a process involving virtual DOM diffing and updates.

Component Update Trigger Mechanism

function setupRenderEffect(instance, vnode, container) {
  instance.update = effect(() => {
    if (!instance.isMounted) {
      // Initial render
      const subTree = instance.render()
      patch(null, subTree, container)
      instance.isMounted = true
    } else {
      // Update
      const nextTree = instance.render()
      const prevTree = instance.subTree
      patch(prevTree, nextTree, container)
      instance.subTree = nextTree
    }
  }, {
    scheduler: queueJob
  })
}

Handling Edge Cases in the Reactive System

Various special scenarios must be considered in real-world applications to ensure the stability and reliability of the reactive system.

Handling Circular References

function reactive(target) {
  if (reactiveMap.has(target)) {
    return reactiveMap.get(target)
  }
  // ...remaining Proxy creation logic
}

Reactive Conversion of Primitive Values

function toReactive(value) {
  return isObject(value) ? reactive(value) : value
}

Debugging Support in the Reactive System

In development environments, detailed debugging information is provided to help developers understand reactive behavior.

function track(target, key) {
  if (__DEV__ && !activeEffect) {
    console.warn(`Property "${String(key)}" was accessed without an active effect`)
  }
  // ...normal track logic
}

Integration of the Reactive System with TypeScript

Vue 3's reactive system is entirely written in TypeScript, offering comprehensive type support.

interface ReactiveEffect<T = any> {
  (): T
  _isEffect: true
  id: number
  active: boolean
  raw: () => T
  deps: Array<Dep>
  options: ReactiveEffectOptions
}

interface ReactiveEffectOptions {
  lazy?: boolean
  scheduler?: (job: ReactiveEffect) => void
  onTrack?: (event: DebuggerEvent) => void
  onTrigger?: (event: DebuggerEvent) => void
  onStop?: () => void
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.