背景 前端性能这件事,经常有两个极端:
一种是完全不管,页面卡了再说 另一种是上来就讲虚拟列表、SSR、代码分割,结果项目里真正拖慢页面的点根本不在那 Vue3 本身已经做了不少优化,但框架快,不代表业务代码就一定快。
真正影响体验的,通常还是这些问题:
不必要的响应式开销 大列表重复渲染 首屏加载资源过大 watch 写得太随意,副作用失控 这篇文章只聊实战里最常见、最值回票价的优化点。
先判断瓶颈在哪 优化前先确认问题类型。通常分三类:
首屏慢 JS 包太大、资源太多、接口太慢。 交互卡 某个状态变更引起大面积重渲染。 长列表卡 DOM 数量过多,滚动和 patch 开销都很高。 这三类问题的解决手段完全不同。不要把“页面卡”都归因到 Vue 响应式。
不要把所有东西都塞进 reactive 很多项目里常见这种写法:
const state = reactive({ tableData: [], chartInstance: null, editor: null, wsConnection: null, filters: { keyword: '', status: 'all', }, }) 看起来统一,实际上问题不少。
像图表实例、编辑器对象、WebSocket 连接这种第三方对象,本来就不是拿来做细粒度响应式追踪的。把它们塞进深层响应式对象里,只会增加代理成本,还可能带来奇怪副作用。
更合理的拆法是:
import { reactive, shallowRef, markRaw } from 'vue' const filters = reactive({ keyword: '', status: 'all', }) const tableData = shallowRef<User[]>([]) const chartInstance = shallowRef<any>(null) const editor = shallowRef<any>(null) function initChart(el: HTMLDivElement) { chartInstance.value = markRaw(createChart(el)) } 这里的思路很明确:
业务表单状态,用 reactive 大数组、外部实例,用 shallowRef 不希望被代理的对象,用 markRaw 这不是“写法偏好”,而是直接影响更新成本。
...