阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 响应式系统的性能优化手段

响应式系统的性能优化手段

作者:陈川 阅读数:55586人阅读 分类: Vue.js

响应式系统的核心机制

Vue3的响应式系统基于Proxy实现,相比Vue2的Object.defineProperty有显著改进。核心是通过track和trigger函数建立依赖收集和触发更新的机制:

const targetMap = new WeakMap()

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

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

响应式数据结构的优化

扁平化响应式对象

Vue3对嵌套对象处理进行了优化,不再递归转换所有属性:

const obj = reactive({
  nested: {
    a: 1
  }
})

// Vue2会递归转换nested对象
// Vue3只在访问nested时才进行转换
console.log(obj.nested) // 此时才创建nested的Proxy

原始值包装

对原始值采用ref包装,避免不必要的响应式开销:

const count = ref(0) // 创建具有value属性的响应式引用

// 内部实现简化版
function ref(value) {
  return {
    get value() {
      track(this, 'value')
      return value
    },
    set value(newVal) {
      value = newVal
      trigger(this, 'value')
    }
  }
}

依赖收集优化策略

懒追踪依赖

Vue3只在effect首次运行时收集实际使用的依赖:

const obj = reactive({ a: 1, b: 2 })

effect(() => {
  // 只有obj.a被访问时才收集依赖
  console.log(obj.a ? obj.b : 0)
})

// 修改未访问的属性不会触发effect
obj.c = 3 // 无效果

依赖关系缓存

通过effectStack缓存当前执行的effect,避免重复收集:

let effectStack = []

function effect(fn) {
  const e = () => {
    if (effectStack.includes(e)) return
    try {
      effectStack.push(e)
      return fn()
    } finally {
      effectStack.pop()
    }
  }
  e()
  return e
}

批量更新与调度

异步更新队列

通过nextTick实现批量更新,减少不必要的DOM操作:

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() {
  queue.sort((a, b) => a.id - b.id)
  for (let i = 0; i < queue.length; i++) {
    queue[i]()
  }
  queue.length = 0
  isFlushing = false
}

自定义调度器

允许自定义更新触发逻辑:

effect(() => {
  console.log(obj.a)
}, {
  scheduler(effect) {
    // 控制更新时机
    requestIdleCallback(effect)
  }
})

编译时优化

PatchFlag标记

编译器分析模板生成优化提示:

<div>
  <div :class="{ active: isActive }"></div>
  <div>{{ dynamicText }}</div>
</div>

编译后生成的渲染函数包含PatchFlag:

function render() {
  return (_openBlock(), _createBlock("div", null, [
    _createVNode("div", { class: _normalizeClass({ active: _ctx.isActive }) }, null, 2 /* CLASS */),
    _createVNode("div", null, _toDisplayString(_ctx.dynamicText), 1 /* TEXT */)
  ]))
}

静态提升

将静态节点提升到渲染函数外部:

const _hoisted_1 = _createVNode("div", null, "static content")

function render() {
  return (_openBlock(), _createBlock("div", null, [
    _hoisted_1,
    _createVNode("div", null, _ctx.dynamicContent)
  ]))
}

响应式API的细粒度控制

shallowReactive

创建浅层响应式对象:

const shallow = shallowReactive({
  nested: { a: 1 }
})

// 只有shallow本身是响应式的
shallow.nested.a = 2 // 不会触发更新

markRaw

标记对象永不转为响应式:

const foo = markRaw({})
const obj = reactive({ foo }) // obj.foo不会被代理

内存管理优化

WeakMap使用

使用WeakMap存储依赖关系,避免内存泄漏:

const targetMap = new WeakMap() // key是普通对象时不会阻止垃圾回收

function getDeps(target) {
  let depsMap = targetMap.get(target)
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()))
  }
  return depsMap
}

响应式对象缓存

对同一原始对象返回相同Proxy:

const reactiveMap = new WeakMap()

function reactive(target) {
  let proxy = reactiveMap.get(target)
  if (!proxy) {
    proxy = new Proxy(target, handlers)
    reactiveMap.set(target, proxy)
  }
  return proxy
}

性能监测与调试

响应式追踪

开发模式下可追踪属性访问:

function track(target, key) {
  if (!activeEffect || !shouldTrack) return
  // ...
  if (__DEV__) {
    debugger // 可在此处添加调试逻辑
  }
}

性能标记

使用performance API测量关键操作耗时:

function trigger(target, key) {
  const start = performance.now()
  // ...触发逻辑
  const duration = performance.now() - start
  if (duration > 10) {
    console.warn(`Long trigger duration: ${duration}ms`)
  }
}

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

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

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌