web-performance-optimization

web-performance-optimization

热门

优化网站和 Web 应用的性能,包括加载速度、Core Web Vitals、打包体积、缓存策略和运行时性能

4.4万Star
6503Fork
更新于 2026/7/29
SKILL.md
readonly只读
name
web-performance-optimization
description

优化网站和 Web 应用的性能,包括加载速度、Core Web Vitals、打包体积、缓存策略和运行时性能

Web 性能优化

概述

帮助开发者优化网站和 Web 应用的性能,以提升用户体验、SEO 排名和转化率。本技能提供系统化的方法来测量、分析和改进加载速度、运行时性能以及 Core Web Vitals 指标。

何时使用此技能

  • 当网站或应用加载缓慢时
  • 当优化 Core Web Vitals(LCP、FID、CLS)时
  • 当减少 JavaScript 打包体积时
  • 当改进可交互时间(TTI)时
  • 当优化图片和资源时
  • 当实现缓存策略时
  • 当调试性能瓶颈时
  • 当准备性能审计时

工作原理

步骤 1:测量当前性能

我将帮助你建立基线指标:

  • 运行 Lighthouse 审计
  • 测量 Core Web Vitals(LCP、FID、CLS)
  • 检查打包体积
  • 分析网络瀑布图
  • 识别性能瓶颈

步骤 2:识别问题

分析性能问题:

  • 大型 JavaScript 打包
  • 未优化的图片
  • 阻塞渲染的资源
  • 服务器响应时间慢
  • 缺少缓存头
  • 布局偏移
  • 阻塞主线程的长任务

步骤 3:确定优化优先级

聚焦高影响改进:

  • 关键渲染路径优化
  • 代码分割和懒加载
  • 图片优化
  • 缓存策略
  • 第三方脚本优化

步骤 4:实施优化

应用性能改进:

  • 优化资源(图片、字体、CSS、JS)
  • 实现代码分割
  • 添加缓存头
  • 懒加载非关键资源
  • 优化关键渲染路径

步骤 5:验证改进

测量变更的影响:

  • 重新运行 Lighthouse 审计
  • 比较优化前后的指标
  • 监控真实用户指标(RUM)
  • 在不同设备和网络下测试

示例

示例 1:优化 Core Web Vitals

## 性能审计结果

### 当前指标(优化前)
- **LCP(最大内容绘制):** 4.2s ❌(应小于 2.5s)
- **FID(首次输入延迟):** 180ms ❌(应小于 100ms)
- **CLS(累积布局偏移):** 0.25 ❌(应小于 0.1)
- **Lighthouse 评分:** 62/100

### 识别的问题

1. **LCP 问题:** 首屏图片(2.5MB)加载缓慢
2. **FID 问题:** 大型 JavaScript 包(850KB)阻塞主线程
3. **CLS 问题:** 图片缺少尺寸导致布局偏移

### 优化计划

#### 修复 LCP(最大内容绘制)

**问题:** 首屏图片大小为 2.5MB,加载缓慢

**解决方案:**
\`\`\`html
<!-- 优化前:未优化的图片 -->
<img src="/hero.jpg" alt="Hero">

<!-- 优化后:使用现代格式 -->
<picture>
  <source srcset="/hero.avif" type="image/avif">
  <source srcset="/hero.webp" type="image/webp">
  <img 
    src="/hero.jpg" 
    alt="Hero"
    width="1200" 
    height="600"
    loading="eager"
    fetchpriority="high"
  >
</picture>
\`\`\`

**额外优化:**
- 压缩图片至 < 200KB
- 使用 CDN 加速传输
- 预加载首屏图片:`<link rel="preload" as="image" href="/hero.avif">`

#### 修复 FID(首次输入延迟)

**问题:** 850KB JavaScript 包阻塞主线程

**解决方案:**

1. **代码分割:**
\`\`\`javascript
// 优化前:所有代码在一个包中
import { HeavyComponent } from './HeavyComponent';
import { Analytics } from './analytics';
import { ChatWidget } from './chat';

// 优化后:懒加载非关键代码
const HeavyComponent = lazy(() => import('./HeavyComponent'));
const ChatWidget = lazy(() => import('./chat'));

// 页面交互后加载分析脚本
if (typeof window !== 'undefined') {
  window.addEventListener('load', () => {
    import('./analytics').then(({ Analytics }) => {
      Analytics.init();
    });
  });
}
\`\`\`

2. **移除未使用的依赖:**
\`\`\`bash
# 分析打包
npx webpack-bundle-analyzer

# 移除未使用的包
npm uninstall moment  # 改用 date-fns(更小)
npm install date-fns
\`\`\`

3. **延迟非关键脚本:**
\`\`\`html
<!-- 优化前:阻塞渲染 -->
<script src="/analytics.js"></script>

<!-- 优化后:延迟加载 -->
<script src="/analytics.js" defer></script>
\`\`\`

#### 修复 CLS(累积布局偏移)

**问题:** 图片缺少尺寸导致布局偏移

**解决方案:**
\`\`\`html
<!-- 优化前:无尺寸 -->
<img src="/product.jpg" alt="Product">

<!-- 优化后:指定尺寸 -->
<img 
  src="/product.jpg" 
  alt="Product"
  width="400" 
  height="300"
  style="aspect-ratio: 4/3;"
>
\`\`\`

**对于动态内容:**
\`\`\`css
/* 为稍后加载的内容预留空间 */
.skeleton-loader {
  min-height: 200px;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
}

@keyframes loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
\`\`\`

### 优化后的结果

- **LCP:** 1.8s ✅(提升 57%)
- **FID:** 45ms ✅(提升 75%)
- **CLS:** 0.05 ✅(提升 80%)
- **Lighthouse 评分:** 94/100 ✅

示例 2:减少 JavaScript 打包体积

## 打包体积优化

### 当前状态
- **总打包体积:** 850KB(gzip 后:280KB)
- **主包:** 650KB
- **第三方包:** 200KB
- **加载时间(3G):** 8.2s

### 分析

\`\`\`bash
# 分析打包组成
npx webpack-bundle-analyzer dist/stats.json
\`\`\`

**发现:**
1. Moment.js:67KB(可用 date-fns 替代:12KB)
2. Lodash:72KB(使用了整个库,实际只需 5 个函数)
3. 未使用的代码:约 150KB 死代码
4. 无代码分割:所有代码在一个包中

### 优化步骤

#### 1. 替换重量级依赖

\`\`\`bash
# 移除 moment.js(67KB)→ 使用 date-fns(12KB)
npm uninstall moment
npm install date-fns

# 优化前
import moment from 'moment';
const formatted = moment(date).format('YYYY-MM-DD');

# 优化后
import { format } from 'date-fns';
const formatted = format(date, 'yyyy-MM-dd');
\`\`\`

**节省:** 55KB

#### 2. 选择性使用 Lodash

\`\`\`javascript
// 优化前:导入整个库(72KB)
import _ from 'lodash';
const unique = _.uniq(array);

// 优化后:只导入所需部分(5KB)
import uniq from 'lodash/uniq';
const unique = uniq(array);

// 或使用原生方法
const unique = [...new Set(array)];
\`\`\`

**节省:** 67KB

#### 3. 实现代码分割

\`\`\`javascript
// Next.js 示例
import dynamic from 'next/dynamic';

// 懒加载重量级组件
const Chart = dynamic(() => import('./Chart'), {
  loading: () => <div>加载图表中...</div>,
  ssr: false
});

const AdminPanel = dynamic(() => import('./AdminPanel'), {
  loading: () => <div>加载中...</div>
});

// 基于路由的代码分割(Next.js 自动实现)
// pages/admin.js - 仅在访问 /admin 时加载
// pages/dashboard.js - 仅在访问 /dashboard 时加载
\`\`\`

#### 4. 移除死代码

\`\`\`javascript
// 在 webpack.config.js 中启用 tree shaking
module.exports = {
  mode: 'production',
  optimization: {
    usedExports: true,
    sideEffects: false
  }
};

// 在 package.json 中
{
  "sideEffects": false
}
\`\`\`

#### 5. 优化第三方脚本

\`\`\`html
<!-- 优化前:立即加载 -->
<script src="https://analytics.com/script.js"></script>

<!-- 优化后:页面交互后加载 -->
<script>
  window.addEventListener('load', () => {
    const script = document.createElement('script');
    script.src = 'https://analytics.com/script.js';
    script.async = true;
    document.body.appendChild(script);
  });
</script>
\`\`\`

### 结果

- **总打包体积:** 380KB ✅(减少 55%)
- **主包:** 180KB ✅
- **第三方包:** 80KB ✅
- **加载时间(3G):** 3.1s ✅(提升 62%)

示例 3:图片优化策略

## 图片优化

### 当前问题
- 15 张图片,总计 12MB
- 未使用现代格式(WebP、AVIF)
- 无响应式图片
- 无懒加载

### 优化策略

#### 1. 转换为现代格式

\`\`\`bash
# 安装图片优化工具
npm install sharp

# 转换脚本(optimize-images.js)
const sharp = require('sharp');
const fs = require('fs');
const path = require('path');

async function optimizeImage(inputPath, outputDir) {
  const filename = path.basename(inputPath, path.extname(inputPath));
  
  // 生成 WebP
  await sharp(inputPath)
    .webp({ quality: 80 })
    .toFile(path.join(outputDir, \`\${filename}.webp\`));
  
  // 生成 AVIF(最佳压缩)
  await sharp(inputPath)
    .avif({ quality: 70 })
    .toFile(path.join(outputDir, \`\${filename}.avif\`));
  
  // 生成优化的 JPEG 回退
  await sharp(inputPath)
    .jpeg({ quality: 80, progressive: true })
    .toFile(path.join(outputDir, \`\${filename}.jpg\`));
}

// 处理所有图片
const images = fs.readdirSync('./images');
images.forEach(img => {
  optimizeImage(\`./images/\${img}\`, './images/optimized');
});
\`\`\`

#### 2. 实现响应式图片

\`\`\`html
<!-- 使用现代格式的响应式图片 -->
<picture>
  <!-- 支持 AVIF 的浏览器使用(最佳压缩) -->
  <source 
    srcset="
      /images/hero-400.avif 400w,
      /images/hero-800.avif 800w,
      /images/hero-1200.avif 1200w
    "
    type="image/avif"
    sizes="(max-width: 768px) 100vw, 50vw"
  >
  
  <!-- 支持 WebP 的浏览器使用 -->
  <source 
    srcset="
      /images/hero-400.webp 400w,
      /images/hero-800.webp 800w,
      /images/hero-1200.webp 1200w
    "
    type="image/webp"
    sizes="(max-width: 768px) 100vw, 50vw"
  >
  
  <!-- JPEG 回退 -->
  <img 
    src="/images/hero-800.jpg"
    srcset="
      /images/hero-400.jpg 400w,
      /images/hero-800.jpg 800w,
      /images/hero-1200.jpg 1200w
    "
    sizes="(max-width: 768px) 100vw, 50vw"
    alt="Hero image"
    width="1200"
    height="600"
    loading="lazy"
  >
</picture>
\`\`\`

#### 3. 懒加载

\`\`\`html
<!-- 原生懒加载 -->
<img 
  src="/image.jpg" 
  alt="Description"
  loading="lazy"
  width="800"
  height="600"
>

<!-- 首屏图片使用 eager 加载 -->
<img 
  src="/hero.jpg" 
  alt="Hero"
  loading="eager"
  fetchpriority="high"
>
\`\`\`

#### 4. Next.js Image 组件

\`\`\`javascript
import Image from 'next/image';

// 自动优化
<Image
  src="/hero.jpg"
  alt="Hero"
  width={1200}
  height={600}
  priority  // 用于首屏图片
  quality={80}
/>

// 懒加载
<Image
  src="/product.jpg"
  alt="Product"
  width={400}
  height={300}
  loading="lazy"
/>
\`\`\`

### 结果

| 指标 | 优化前 | 优化后 | 提升 |
|--------|--------|-------|-------------|
| 图片总大小 | 12MB | 1.8MB | 减少 85% |
| LCP | 4.5s | 1.6s | 加快 64% |
| 页面加载(3G) | 18s | 4.2s | 加快 77% |

最佳实践

✅ 应该这样做

  • 先测量 - 优化前始终建立基线指标
  • 使用 Lighthouse - 定期运行审计以跟踪进度
  • 优化图片 - 使用现代格式(WebP、AVIF)和响应式图片
  • 代码分割 - 将大型包拆分为更小的块
  • 懒加载 - 延迟非关键资源
  • 积极缓存 - 为静态资源设置适当的缓存头
  • 最小化主线程工作 - 保持 JavaScript 执行在 50ms 块内
  • 预加载关键资源 - 对关键资源使用 <link rel="preload">
  • 使用 CDN - 通过 CDN 提供静态资源以加快传输
  • 监控真实用户 - 跟踪真实用户的 Core Web Vitals

❌ 不要这样做

  • 不要盲目优化 - 先测量,再优化
  • 不要忽略移动端 - 在真实移动设备和慢速网络上测试
  • 不要阻塞渲染 - 避免阻塞渲染的 CSS 和 JavaScript
  • 不要一次性加载所有内容 - 懒加载非关键资源
  • 不要忘记尺寸 - 始终指定图片的宽度和高度
  • 不要使用同步脚本 - 使用 async 或 defer 属性
  • 不要忽略第三方脚本 - 它们经常导致性能问题
  • 不要跳过压缩 - 始终压缩和精简资源

常见陷阱

问题:桌面端优化良好但移动端缓慢

症状: 桌面端 Lighthouse 评分高,移动端差
解决方案:

  • 在真实移动设备上测试
  • 使用 Chrome DevTools 移动端限速
  • 针对 3G/4G 网络优化
  • 减少 JavaScript 执行时间
# 使用限速测试
lighthouse https://yoursite.com --throttling.cpuSlowdownMultiplier=4

问题:大型 JavaScript 包

症状: 可交互时间(TTI)长,FID 高
解决方案:

  • 使用 webpack-bundle-analyzer 分析包
  • 移除未使用的依赖
  • 实现代码分割
  • 懒加载非关键代码
# 分析包
npx webpack-bundle-analyzer dist/stats.json

问题:图片导致布局偏移

症状: CLS 评分高,内容跳动
解决方案:

  • 始终指定宽度和高度
  • 使用 aspect-ratio CSS 属性
  • 使用骨架屏预留空间
img {
  aspect-ratio: 16 / 9;
  width: 100%;
  height: auto;
}

问题:服务器响应时间慢

症状: TTFB(首字节时间)高
解决方案:

  • 实现服务器端缓存
  • 对静态资源使用 CDN
  • 优化数据库查询
  • 考虑静态站点生成(SSG)
// Next.js:静态生成
export async function getStaticProps() {
  const data = await fetchData();
  return {
    props: { data },
    revalidate: 60 // 每 60 秒重新生成
  };
}

性能检查清单

图片

  • [ ] 转换为现代格式(WebP、AVIF)
  • [ ] 实现响应式图片
  • [ ] 添加懒加载
  • [ ] 指定尺寸(宽度/高度)
  • [ ] 压缩图片(每张 < 200KB)
  • [ ] 使用 CDN 传输

JavaScript

  • [ ] 打包体积 < 200KB(gzip 后)
  • [ ] 实现代码分割
  • [ ] 懒加载非关键代码
  • [ ] 移除未使用的依赖
  • [ ] 精简和压缩
  • [ ] 对脚本使用 async/defer

CSS

  • [ ] 内联关键 CSS
  • [ ] 延迟非关键 CSS
  • [ ] 移除未使用的 CSS
  • [ ] 精简 CSS 文件
  • [ ] 使用 CSS containment

缓存

  • [ ] 为静态资源设置缓存头
  • [ ] 实现 Service Worker
  • [ ] 使用 CDN 缓存
  • [ ] 缓存 API 响应
  • [ ] 对静态资源进行版本管理

Core Web Vitals

  • [ ] LCP < 2.5s
  • [ ] FID < 100ms
  • [ ] CLS < 0.1
  • [ ] TTFB < 600ms
  • [ ] TTI < 3.8s

性能工具

测量工具

  • Lighthouse - 全面的性能审计
  • WebPageTest - 详细的瀑布图分析
  • Chrome DevTools - 性能分析
  • PageSpeed Insights - 真实用户指标
  • Web Vitals 扩展 - 监控 Core Web Vitals

分析工具

  • webpack-bundle-analyzer - 可视化包组成
  • source-map-explorer - 分析包大小
  • Bundlephobia - 安装前检查包大小
  • ImageOptim - 图片压缩工具

监控工具

  • Google Analytics - 跟踪 Core Web Vitals
  • Sentry - 性能监控
  • New Relic - 应用性能监控
  • Datadog - 真实用户监控

相关技能

  • @react-best-practices - React 性能模式
  • @frontend-dev-guidelines - 前端开发标准
  • @systematic-debugging - 调试性能问题
  • @senior-architect - 性能架构

额外资源


专业提示: 首先关注 Core Web Vitals(LCP、FID、CLS)——它们对用户体验和 SEO 排名影响最大!

限制

  • 仅当任务明确符合上述范围时使用此技能。
  • 不要将输出视为环境特定验证、测试或专家审查的替代品。
  • 如果缺少所需的输入、权限、安全边界或成功标准,请停止并请求澄清。