响应式系统的性能优化手段
响应式系统的核心机制
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
下一篇:手动停止响应的方法