前端性能优化清单:不改架构也能快一倍
性能优化听起来玄学,但 80% 的收益来自几件确定能做的小事。按「传输 → 缓存 → 资源 → 渲染」四层来做,每层都有可验证的指标。
一、先量再改
# 首字节时间 + 总耗时
curl -o /dev/null -s -w "dns=%{time_namelookup} connect=%{time_connect} ttfb=%{time_starttransfer} total=%{time_total}\n" https://www.bzii.cn
# 各资源耗时瀑布图(命令行版)
curl -w "@curl-format.txt" -o /dev/null -s https://www.bzii.cn浏览器里用 DevTools 的 Network 面板看 DOMContentLoaded 和 Load,再用 Lighthouse 跑分。
二、传输层:压缩必须开
# gzip(兼容性最好)
gzip on;
gzip_vary on;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript
text/xml application/xml image/svg+xml;# 验证
curl -sI -H "Accept-Encoding: gzip" https://www.bzii.cn | grep -i content-encoding如果 Nginx 编译时带了 brotli 模块,优先用它(比 gzip 小 15~20%):
brotli on;
brotli_comp_level 5;
brotli_types text/css application/javascript application/json image/svg+xml;HTML/CSS/JS 压缩收益最大(通常 70%+);图片、视频本来就是压缩格式,不要对它们开 gzip,白费 CPU。
三、缓存层:静态资源长缓存
# 带 hash 的文件名:放心缓存一年
location ~* .[0-9a-f]{8,}.(css|js)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# 普通静态资源
location ~* .(css|js|png|jpg|jpeg|gif|svg|webp|woff2)$ {
expires 30d;
add_header Cache-Control "public";
}
# HTML 不缓存(否则发新版用户看不到)
location = /index.html {
add_header Cache-Control "no-cache";
}核心原则:文件名带内容 hash,就可以 immutable;不带 hash,就不能缓存太久。
四、资源层:图片是最大的体积来源
| 优化项 | 做法 | 收益 |
|---|---|---|
| 格式 | 转 WebP / AVIF,比 JPEG 小 30~50% | 高 |
| 尺寸 | 按需生成,别用 2000px 的图当缩略图 | 高 |
| 懒加载 | <img loading="lazy"> | 中 |
| 预声明 | 首屏图加 <link rel="preload"> | 中 |
| 图标 | 用 SVG 或图标字体,别用 PNG | 中 |
# 批量转 WebP(cwebp)
sudo apt install -y webp
cwebp -q 80 input.jpg -o output.webp
# 批量压缩 JPEG/PNG
jpegoptim --max=85 *.jpg
optipng -o2 *.png五、渲染层:别让 CSS/JS 挡住首屏
<!-- 关键 CSS 内联,其余异步加载 -->
<style>/* 首屏必要样式 */</style>
<link rel="preload" href="/style.css" as="style" onload="this.rel='stylesheet'">
<!-- 非关键 JS 延后 -->
<script src="/app.js" defer></script>
<!-- 图片懒加载 + 尺寸声明(防布局抖动) -->
<img src="a.webp" loading="lazy" width="800" height="450" alt="">几个要点:
defer优于async(保持执行顺序、不阻塞解析);- 图片必须写
width/height,否则加载过程中页面会跳(CLS 指标变差); - 字体用
font-display: swap,避免文字空白期。
六、HTTP/2 与 HTTP/3
listen 443 ssl http2;
listen [::]:443 ssl http2;
# 有 quic 支持可以再加
listen 443 quic reuseport;
add_header Alt-Svc 'h3=":443"; ma=86400';HTTP/2 的多路复用意味着不用再合并文件,反而拆成多个小文件更利于缓存。
七、零依赖站点特别适用的一条
像本站这种不引框架的做法,全站 JS 不到 30KB、无第三方请求,首屏基本只有一次 HTML + 一次 CSS + 一次 JS 请求。 这比「引了 React + 一堆库再做优化」要省事得多——最有效的优化往往是不加载。
八、验证清单
content-encoding: gzip/br存在- 静态资源
cache-control正确 - 图片是 WebP 且尺寸合理
- Lighthouse Performance ≥ 90
- CLS(布局偏移)< 0.1
# 一键看响应头
curl -sI https://www.bzii.cn | grep -iE "content-encoding|cache-control|server"