一句话总结
按三个维度组织答案:加载快——路由/组件懒加载、按需引入组件库、CDN + gzip、图片懒加载;渲染快——keep-alive 缓存、虚拟列表、合理 v-show、骨架屏;更新快——key 正确、v-memo/v-once、shallowRef/markRaw 减少响应式开销、防内存泄漏。回答时先讲"测量"(Lighthouse/Performance 面板)再讲"手段",体现工程素养。
初级理解
路由懒加载(必答的第一条):SPA 把所有页面打进一个 bundle 是首屏慢的最大原因。Vue Router 的异步组件语法让每个页面成为独立 chunk,访问时才加载。
图片懒加载:列表图片用 loading="lazy" 原生属性或 IntersectionObserver 实现,未进入视口不请求。
v-if vs v-show 的性能选型:不常切换的模块用 v-if(不渲染省内存);频繁切换用 v-show(避免反复销毁重建)。
中级深入
首屏优化清单(按收益排序):
- 构建产物分析:rollup-plugin-visualizer(Vite)/ webpack-bundle-analyzer 找到大头
- 组件库按需引入:Element Plus / Ant Design Vue 用 unplugin-vue-components 自动按需,或改用 $fetch 弹性加载
- 大依赖 externals + CDN(echarts、moment 换 dayjs)
- gzip/brotli:Nginx 或构建期预压缩 vite-plugin-compression
- 骨架屏 + 路由过渡动画掩盖白屏;关键接口 SSRF/预取(preload、modulepreload)
keep-alive 缓存页面/组件:搜索列表 → 详情 → 返回列表不重新请求;用 include + max 精确控制缓存集,防内存无限增长。
长列表必用虚拟滚动:DOM 只渲染可视区 + 上下缓冲区(如 1 万条只渲染 20 条),vueuse 的 useVirtualList 或 vue-virtual-scroller;同时配合 Object.freeze / markRaw 让大静态数据不进响应式系统。
高级拓展
更新性能:减少不必要的响应式开销
内存泄漏排查(Vue 特有坑):卸载后仍然存活的定时器、事件监听、第三方实例是三大来源。组合式 API 里 onMounted 注册的 addEventListener/setInterval 必须在 onUnmounted 清理;直接在 setup 同步注册的监听(watch/onMounted 内部会自动清理的除外)注意作用域。Chrome Memory 面板对比两次快照找 Detached DOM。
进阶手段与时机:
- Worker:万级数据解析/计算移到 Web Worker,防长任务阻塞主线程(INP 指标)
- 防抖节流:resize/scroll/输入联想是标配
- SSR(Nuxt)/SSG:对 SEO + 首屏都有硬指标要求时才上,复杂度翻倍要想清楚
- 预渲染:营销页用 vite-plugin-prerender 静态化,比 SSR 便宜得多
实战场景
场景一:万行表格全选卡死
场景二:打包体积从 4MB 降到 1.2MB
场景三:切换路由后定时器仍在跑
面试模拟
Q:Vue3 的编译优化对性能优化有什么实际影响?
A:很多"手动优化"被编译器自动做了——静态节点自动提升、动态点自动打 PatchFlag、inline 事件自动缓存。所以 Vue3 项目里性能优化重点从"少写让 diff 白跑的代码"转向数据层:正确响应式粒度(shallowRef/markRaw)、虚拟滚动、懒加载。这也是面试里区分"背 Vue2 优化清单"和"真用过 Vue3"的点。
Q:虚拟列表的原理?滚动时怎么不卡?
A:容器内放一个总高度撑开的占位层(撑出真实滚动条),可视窗口只渲染"起始索引 ~ 结束索引"的数据,滚动时用 scrollTop 算出 startIndex,用 transform 偏移当前片段。优化点:scroll 监听 rAF 节流、上下各加 5~10 条缓冲区防白屏、不定高行用估算高度 + 渲染后校正(缓存已测高度)。
Q:怎么定位一个页面"慢"到底慢在哪?
A:先分清慢的类型——网络慢看 Network(瀑布图、TTFB、资源体积),渲染慢看 Performance 面板(长任务、Layout/Paint 占比),交互慢看长任务与 INP,内存问题看 Memory 快照。Vue 特有手段:用 app.config.performance = true 或 Vue Devtools 的 Inspector 看组件渲染耗时。结论必须落到数据:哪个指标从多少降到多少。