一、编译阶段的优化
1. 静态提升(Static Hoisting)
- 机制:将模板中不变的静态节点(如纯文本、无绑定的元素)提取为常量,在渲染函数外生成一次,后续复用。 示例:
const _hoisted_1 = createVNode('p', null, '静态文本'); // 编译阶段提升
function render() {
return [_hoisted_1, createVNode('div', null, this.dynamicData)];
}
-
优势:
- 避免每次渲染时重复创建静态节点,减少内存消耗和虚拟 DOM 生成时间
- 结合 预字符串化(Pre-stringification) ,将大量静态内容直接编译为字符串,进一步优化运行时性能
2. 动态标记(Patch Flag)
- 机制:为动态节点 (如绑定变量、事件) 添加标记(如
`1`表示文本变化,`8`表示属性变化),指导运行时仅对比标记部分。 示例:
createVNode('p', { class: dynamicClass }, '文本', 2 /* CLASS 动态标记 */);
-
优势:
- 精准识别动态变化点,跳过无变化的静态内容,减少 Diff 范围,性能提升 30%~50%
3. 分块树(Block Tree)
- 机制:将模板划分为动态块(Block)和静态块,每个块包含关联的动态子树,更新时仅处理动态块。 示例:
function render() {
return createBlock('div', [dynamicBlock, _hoisted_1]); // 仅 dynamicBlock 参与 Diff
}
-
优势:
- 减少 Diff 深度和范围,尤其对大型列表和复杂组件效果显著
4. 事件监听缓存
- 机制:若事件处理函数无依赖动态数据,则将其缓存为常量,避免每次渲染重新创建。 示例:
const cachedHandler = () => console.log('click');
function render() {
return createVNode('button', { onClick: cachedHandler });
}
-
优势:
- 减少函数创建和内存占用,优化高频交互场景(如列表点击)
5. 指令优化(v-once 与 v-memo)
-
v-once:标记只渲染一次的静态内容,后续跳过 Diff。
-
v-memo:缓存动态节点的渲染结果,依赖项不变时直接复用。
-
优势:
- 避免不必要的重复计算,适用于表格、大列表等场景
6. SSR 优化
- 预字符串化:将静态内容直接编译为 HTML 字符串,减少服务端渲染时的虚拟 DOM 生成开销
二、渲染阶段的优化
1. 快速 Diff 算法(Fast Diff)
-
机制:
- 预处理新旧子节点,通过 双端对比 和 最长递增子序列 算法减少 DOM 操作。
-
示例: 新旧子节点序列
`[A,B,C,D]`→`[A,C,B,D]`,仅移动`C`和`B`,而非全量更新。 -
优势:
- 减少 DOM 移动次数,性能提升 2~3 倍
2. Fragment 支持
- 机制:允许组件有多个根节点,无需包裹额外元素。 示例:
<template>
<header>...</header>
<main>...</main>
</template>
-
优势:
- 减少冗余 DOM 层级,提升渲染效率(Vue 2 需强制单根节点)
3. 响应式系统升级
-
Proxy 代理:
-
替代 Vue 2 的
`Object.defineProperty`,支持动态属性增删和数组索引修改。 -
优势:
- 无需
`Vue.set`/`Vue.delete`,简化开发 - 按需触发更新,避免全量递归监听,内存占用降低 40%
- 无需
-
4. 异步渲染与调度
- vue2
- setTimeout
- 无优先级
- 可能无限循环
- 延迟高
-
vue3
-
Promise.then() -> 降级到 mutationObserver -> setTimeout
-
按id和pre排序
-
通过 allowRecurse & flushIndex 控制不无限递归
-
低延迟
为什么宏任务不能实现批处理
- 一个宏任务执行完毕后会清空微任务队列
- 执行顺序可能由于浏览器不同而不稳定
- 不同的宏任务是隔离上下文的 (而微任务是共享上下文的 )
-
机制:
- 将多次数据变更合并为单次渲染任务,通过微任务队列调度更新。
- 使用Promise.then() 包装成微任务执行,确保异步批量更新
- 通过任务 id 排序优先级
-
优势:
- 避免频繁重绘,优化高频操作(如实时输入、滚动)的流畅度
笔者才疏学浅,各位读者多多担待,不吝赐教。部分插图来自网络,侵删。