前端性能优化手段
一、网络层优化
减少请求数量
✅ 合并 CSS / JS 文件
✅ 雪碧图(CSS Sprite)合并小图标
✅ 图标使用 SVG / IconFont 代替图片
✅ 接口合并,减少 HTTP 请求
⚠️ 注意:HTTP/2 下,"合并文件"的收益大幅降低
HTTP/2 多路复用允许在单个 TCP 连接上并行发送多个请求,请求头也经过 HPACK 压缩,每次请求的额外开销极小。 因此在 HTTP/2 环境下,反而推荐拆分资源(细粒度缓存,更新一个文件不影响其他文件的缓存)。
场景 HTTP/1.1 HTTP/2 并发请求 受浏览器限制(约 6 个) 单连接无限制并行 合并文件收益 很大 降低,反而不利于缓存 请求 Header 开销 每次完整发送 HPACK 压缩,极小
开启 HTTP/2
HTTP/2 是提升网络性能的重要手段,使用前需了解其触发条件:
如何开启:
- 服务端配置支持 HTTP/2(以 Nginx 为例):
server {
listen 443 ssl http2;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
...
}
- 浏览器支持(现代浏览器均支持)
一定需要 HTTPS 吗?
- HTTP/2 协议规范(RFC 7540)允许明文 HTTP/2(h2c),不强制 TLS
- 但所有主流浏览器(Chrome / Firefox / Safari / Edge)均只实现了基于 TLS 的 HTTP/2
- 结论:Web 前端场景下,HTTP/2 = 必须 HTTPS
减少请求体积
✅ 代码压缩(Gzip / Brotli)
✅ 图片压缩(WebP 格式,体积比 JPG 小 30%)
✅ Tree Shaking 去除未使用代码
✅ 按需引入组件库(如 Element Plus)
缓存策略
✅ 强缓存:Cache-Control: max-age=31536000
✅ 协商缓存:ETag / Last-Modified
✅ 文件名加 hash(content hash),更新才改变文件名
✅ Service Worker 离线缓存
CDN 加速
✅ 静态资源部署 CDN(就近访问)
✅ 第三方库使用 CDN 引入(Vue、React、lodash)
二、资源加载优化
图片优化
✅ 懒加载(loading="lazy" / IntersectionObserver)
✅ 预加载关键图片(<link rel="preload">)
✅ 响应式图片(srcset 按屏幕分辨率加载)
✅ 使用 WebP / AVIF 现代格式
✅ 小图转 base64 内联(< 4KB)
SVG + SVGO 与 WebP 的选择
这两者适用于不同场景,不能互相替代:
| 格式 | 适用场景 | 压缩工具 | 兼容性 |
|---|---|---|---|
| SVG | 图标、Logo、插画、需要缩放的矢量图 | SVGO(可减少体积 30%~60%) | ✅ 极好,IE9+ 全支持 |
| WebP | 照片、截图、复杂位图(替代 JPG/PNG) | 原生格式即压缩,比 JPG 小 25%~35% | ✅ 现代浏览器;❌ IE 不支持 |
WebP 兼容性详情:
| 浏览器 | 支持情况 |
|---|---|
| Chrome | ✅ 17+ |
| Firefox | ✅ 65+ |
| Safari | ✅ 14+(2020年) |
| Edge | ✅ |
| IE | ❌ 完全不支持 |
选择原则:
- 图标 / Logo / 插画 → SVG + SVGO 压缩
- 照片 / 背景图 / 复杂图片 → WebP(搭配
<picture>标签做降级兼容)
WebP 降级方案:
<picture>
<source srcset="image.webp" type="image/webp" />
<img src="image.jpg" alt="降级为 JPG" />
</picture>
JS 优化
✅ 不阻塞 HTML 解析
<!-- defer:HTML 解析完再执行,保持顺序 -->
<script defer src="app.js"></script>
<!-- async:下载完立即执行,不保证顺序 -->
<script async src="analytics.js"></script>
✅ 路由懒加载(动态 import)
✅ 组件异步加载
✅ 第三方库按需引入
CSS 优化
✅ 关键 CSS 内联到 (首屏样式)
✅ 非关键 CSS 异步加载
✅ 减少 @import(会阻塞渲染)
三、渲染性能优化
减少重排重绘
回流 / Reflow / Layout 是同一个概念
三个名词来自不同的引擎,本质完全相同:
| 名词 | 来源 |
|---|---|
| Reflow(回流) | 早期 Gecko(Firefox)引擎术语 |
| Layout(布局) | Blink(Chrome)/ WebKit 引擎术语,DevTools 中显示的名称 |
| 重排 | 中文通用翻译 |
回流的准确定义
回流是指浏览器重新计算页面中元素的几何信息(位置、尺寸)并重新布局的过程。
触发条件(不止是尺寸变化,以下情况均会触发):
| 触发原因 | 典型属性 / 操作 |
|---|---|
| 元素尺寸变化 | width / height / padding / margin / border |
| 元素位置变化 | top / left / position |
| 内容变化 | 文字内容改变、图片尺寸改变 |
| DOM 结构变化 | 增删节点、移动节点 |
| 读取布局属性 | offsetWidth / scrollTop / getBoundingClientRect() |
| 视口变化 | 浏览器窗口 resize |
| 字体变化 | font-size / font-family |
⚠️ 特别注意:在循环中读取
offsetWidth等布局属性,会强制浏览器在每次循环中同步执行 Layout,性能极差(强制同步布局)。
渲染流水线与性能代价
JS → Style → Layout(回流)→ Paint(重绘)→ Composite(合成)
↑ 越靠前触发,代价越大
| 操作 | 触发阶段 | 性能代价 |
|---|---|---|
改 width / display | Layout + Paint + Composite | 最高 ❌ |
改 color / background-color | Paint + Composite | 中等 ⚠️ |
改 transform / opacity | 只触发 Composite | 最低 ✅ |
💡 动画优化原则:尽量只触发 Composite(合成),即使用
transform和opacity做动画,利用 GPU 加速。
减少回流示例:
// ❌ 分散修改,触发多次回流
el.style.width = "100px";
el.style.height = "100px";
el.style.margin = "10px";
// ✅ 批量修改(className / cssText)
el.className = "new-style";
// 或者
el.style.cssText = "width:100px; height:100px; margin:10px";
✅ 使用 transform / opacity 做动画(不触发重排)
✅ 使用 will-change 提示浏览器开启 GPU 加速
✅ 避免频繁读取 offsetWidth / scrollTop 等布局属性
✅ 使用 position: absolute/fixed 脱离文档流
虚拟列表(大数据渲染)
✅ 只渲染可视区域的列表项
✅ 库:vue-virtual-scroller、vue3-virtual-scroll-list
// 核心思路
const visibleCount = Math.ceil(containerHeight / itemHeight);
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = startIndex + visibleCount;
const visibleList = list.slice(startIndex, endIndex);
四、代码层优化
JS 优化
// ✅ 防抖:输入框搜索
const search = debounce((val) => fetchData(val), 300);
// ✅ 节流:scroll / resize 事件
const handleScroll = throttle(() => updateUI(), 100);
// ✅ 使用 Web Worker 处理耗时计算(不阻塞主线程)
const worker = new Worker("./heavy-task.js");
worker.postMessage(data);
worker.onmessage = (e) => console.log(e.data);
// ✅ requestAnimationFrame 替代 setTimeout 做动画
requestAnimationFrame(() => updateAnimation());
Vue 优化
✅ v-for 必须加 key
✅ v-if 和 v-show 合理使用
✅ 大组件异步加载(defineAsyncComponent)
✅ computed 缓存计算结果
✅ 合理使用 keep-alive 缓存组件
✅ 避免在模板中写复杂表达式
✅ 长列表使用 v-memo / Object.freeze 冻结
// 冻结不需要响应式的大数据
this.list = Object.freeze(largeList);
五、构建优化(Webpack / Vite)
// vite.config.js
export default {
build: {
rollupOptions: {
output: {
// 分包策略
manualChunks: {
"vue-vendor": ["vue", "vue-router", "pinia"],
"ui-vendor": ["element-plus"],
},
},
},
// 开启压缩
minify: "terser",
// 小于 4KB 转 base64
assetsInlineLimit: 4096,
},
};
✅ 路由分包,按需加载
✅ 公共库单独打包(vendor chunk)
✅ 生产环境去除 console.log
✅ 开启 Gzip/Brotli 压缩
六、用户体验层优化
✅ 骨架屏(Skeleton)代替白屏等待
✅ Loading 状态反馈
✅ 预渲染(SSG)/ 服务端渲染(SSR)提升首屏
✅ 关键资源 DNS 预解析
<link rel="dns-prefetch" href="//cdn.example.com" />
<link rel="preconnect" href="//api.example.com" />
七、性能优化总览
| 分类 | 关键手段 |
|---|---|
| 网络 | CDN、缓存、Gzip、减少请求 |
| 资源 | 图片懒加载/压缩、JS defer/async、按需加载 |
| 渲染 | 减少重排重绘、GPU加速、虚拟列表 |
| 代码 | 防抖节流、Web Worker、Vue computed |
| 构建 | Tree Shaking、分包、代码压缩 |
| 体验 | 骨架屏、SSR/SSG、预加载 |
性能优化的核心原则:
- 减少资源体积
- 减少请求次数
- 加快请求速度
- 减少渲染工作量
- 提升用户感知体验