🚀 快速安装
复制以下命令并运行,立即安装此 Skill:
npx skills add https://github.com/addyosmani/web-quality-skills --skill performance
💡 提示:需要 Node.js 和 NPM
性能优化
基于 Lighthouse 性能审核的深度性能优化。重点关注加载速度、运行时效率和资源优化。
工作原理
- 识别代码和资产中的性能瓶颈
- 根据对核心 Web 指标的影响确定优先级
- 提供带有代码示例的特定优化方案
- 通过优化前后的指标衡量改进效果
性能预算
| 资源 | 预算 | 理由 |
|---|---|---|
| 总页面大小 | < 1.5 MB | 3G 网络约 4 秒加载完成 |
| JavaScript(压缩后) | < 300 KB | 解析和执行时间 |
| CSS(压缩后) | < 100 KB | 阻塞渲染 |
| 图片(首屏以上) | < 500 KB | 影响最大内容绘制 |
| 字体 | < 100 KB | 防止不可见文本闪烁/样式化文本闪烁 |
| 第三方脚本 | < 200 KB | 不可控的延迟 |
关键渲染路径
服务器响应
- 首字节时间 < 800ms。 首字节时间应尽可能快。使用 CDN、缓存和高效的后端。
- 启用压缩。 对文本资产使用 Gzip 或 Brotli。首选 Brotli(体积小 15-20%)。
- HTTP/2 或 HTTP/3。 多路复用减少连接开销。
- 边缘缓存。 尽可能在 CDN 边缘缓存 HTML。
资源加载
预连接到必需的源:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com" crossorigin>
预加载关键资源:
<!-- 最大内容绘制图片 -->
<link rel="preload" href="/hero.webp" as="image" fetchpriority="high">
<!-- 关键字体 -->
<link rel="preload" href="/font.woff2" as="font" type="font/woff2" crossorigin>
延迟非关键 CSS:
<!-- 内联关键 CSS -->
<style>/* 首屏样式 */</style>
<!-- 非关键 CSS -->
<link rel="preload" href="/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/styles.css"></noscript>
JavaScript 优化
延迟非必要脚本:
<!-- 阻塞解析器 (避免) -->
<script src="/critical.js"></script>
<!-- 延迟 (首选) -->
<script defer src="/app.js"></script>
<!-- 异步 (用于独立脚本) -->
<script async src="/analytics.js"></script>
<!-- 模块 (默认延迟) -->
<script type="module" src="/app.mjs"></script>
代码分割模式:
// 基于路由的分割
const Dashboard = lazy(() => import('./Dashboard'));
// 基于组件的分割
const HeavyChart = lazy(() => import('./HeavyChart'));
// 基于功能的分割
if (user.isPremium) {
const PremiumFeatures = await import('./PremiumFeatures');
}
摇树优化最佳实践:
// ❌ 导入整个库
import _ from 'lodash';
_.debounce(fn, 300);
// ✅ 仅导入所需部分
import debounce from 'lodash/debounce';
debounce(fn, 300);
图片优化
格式选择
| 格式 | 用例 | 浏览器支持 |
|---|---|---|
| AVIF | 照片,最佳压缩率 | 92%+ |
| WebP | 照片,良好的后备方案 | 97%+ |
| PNG | 带透明度的图形 | 通用 |
| SVG | 图标、标志、插图 | 通用 |
响应式图片
<picture>
<!-- AVIF 用于现代浏览器 -->
<source
type="image/avif"
srcset="hero-400.avif 400w,
hero-800.avif 800w,
hero-1200.avif 1200w"
sizes="(max-width: 600px) 100vw, 50vw">
<!-- WebP 后备 -->
<source
type="image/webp"
srcset="hero-400.webp 400w,
hero-800.webp 800w,
hero-1200.webp 1200w"
sizes="(max-width: 600px) 100vw, 50vw">
<!-- JPEG 后备 -->
<img
src="hero-800.jpg"
srcset="hero-400.jpg 400w,
hero-800.jpg 800w,
hero-1200.jpg 1200w"
sizes="(max-width: 600px) 100vw, 50vw"
width="1200"
height="600"
alt="主视觉图片"
loading="lazy"
decoding="async">
</picture>
最大内容绘制图片优先级
<!-- 首屏最大内容绘制图片:立即加载,高优先级 -->
<img
src="hero.webp"
fetchpriority="high"
loading="eager"
decoding="sync"
alt="主视觉">
<!-- 首屏以下图片:延迟加载 -->
<img
src="product.webp"
loading="lazy"
decoding="async"
alt="产品">
字体优化
加载策略
/* 系统字体堆栈作为后备 */
body {
font-family: 'Custom Font', -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, sans-serif;
}
/* 防止不可见文本 */
@font-face {
font-family: 'Custom Font';
src: url('/fonts/custom.woff2') format('woff2');
font-display: swap; /* 或 optional(用于非关键字体) */
font-weight: 400;
font-style: normal;
unicode-range: U+0000-00FF; /* 子集化到拉丁字符集 */
}
预加载关键字体
<link rel="preload" href="/fonts/heading.woff2" as="font" type="font/woff2" crossorigin>
可变字体
/* 一个文件代替多个字重 */
@font-face {
font-family: 'Inter';
src: url('/fonts/Inter-Variable.woff2') format('woff2-variations');
font-weight: 100 900;
font-display: swap;
}
缓存策略
缓存控制头
# HTML(短缓存或不缓存)
Cache-Control: no-cache, must-revalidate
# 带哈希的静态资源(不可变)
Cache-Control: public, max-age=31536000, immutable
# 不带哈希的静态资源
Cache-Control: public, max-age=86400, stale-while-revalidate=604800
# API 响应
Cache-Control: private, max-age=0, must-revalidate
Service Worker 缓存
// 静态资源优先从缓存读取
self.addEventListener('fetch', (event) => {
if (event.request.destination === 'image' ||
event.request.destination === 'style' ||
event.request.destination === 'script') {
event.respondWith(
caches.match(event.request).then((cached) => {
return cached || fetch(event.request).then((response) => {
const clone = response.clone();
caches.open('static-v1').then((cache) => cache.put(event.request, clone));
return response;
});
})
);
}
});
运行时性能
避免布局抖动
// ❌ 强制多次重排
elements.forEach(el => {
const height = el.offsetHeight; // 读操作
el.style.height = height + 10 + 'px'; // 写操作
});
// ✅ 批量读取,然后批量写入
const heights = elements.map(el => el.offsetHeight); // 所有读操作
elements.forEach((el, i) => {
el.style.height = heights[i] + 10 + 'px'; // 所有写操作
});
防抖昂贵操作
function debounce(fn, delay) {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => fn(...args), delay);
};
}
// 防抖滚动/调整大小处理程序
window.addEventListener('scroll', debounce(handleScroll, 100));
使用 requestAnimationFrame
// ❌ 可能导致卡顿
setInterval(animate, 16);
// ✅ 与显示刷新同步
function animate() {
// 动画逻辑
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
虚拟化长列表
// 对于超过 100 个项目的列表,仅渲染可见项
// 使用像 react-window, vue-virtual-scroller 这样的库,或原生 CSS:
.virtual-list {
content-visibility: auto;
contain-intrinsic-size: 0 50px; /* 估计的项目高度 */
}
第三方脚本
加载策略
// ❌ 阻塞主线程
<script src="https://analytics.example.com/script.js"></script>
// ✅ 异步加载
<script async src="https://analytics.example.com/script.js"></script>
// ✅ 延迟到交互后
<script>
document.addEventListener('DOMContentLoaded', () => {
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
const script = document.createElement('script');
script.src = 'https://widget.example.com/embed.js';
document.body.appendChild(script);
observer.disconnect();
}
});
observer.observe(document.querySelector('#widget-container'));
});
</script>
外观模式
<!-- 交互前显示静态占位符 -->
<div class="youtube-facade"
data-video-id="abc123"
onclick="loadYouTube(this)">
<img src="/thumbnails/abc123.jpg" alt="视频标题">
<button aria-label="播放视频">▶</button>
</div>
衡量指标
关键指标
| 指标 | 目标值 | 工具 |
|---|---|---|
| 最大内容绘制 | < 2.5s | Lighthouse, CrUX |
| 首次内容绘制 | < 1.8s | Lighthouse |
| 速度指数 | < 3.4s | Lighthouse |
| 总阻塞时间 | < 200ms | Lighthouse |
| 可交互时间 | < 3.8s | Lighthouse |
测试命令
# Lighthouse 命令行
npx lighthouse https://example.com --output html --output-path report.html
# Web Vitals 库
import {onLCP, onINP, onCLS} from 'web-vitals';
onLCP(console.log);
onINP(console.log);
onCLS(console.log);
参考
有关核心 Web 指标的特定优化,请参阅 核心 Web 指标。
📄 原始文档
完整文档(英文):
https://skills.sh/addyosmani/web-quality-skills/performance
💡 提示:点击上方链接查看 skills.sh 原始英文文档,方便对照翻译。
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

评论(0)