Web 性能优化实战指南


为什么性能很重要?

研究表明:

  • 页面加载时间每增加 1 秒,转化率下降 7%
  • 53% 的用户会放弃加载超过 3 秒的页面
  • Google 将页面速度作为 SEO 排名因素

性能指标

Core Web Vitals

Google 定义的三个核心指标:

  1. LCP (Largest Contentful Paint): 最大内容绘制

    • 目标: < 2.5s
    • 衡量加载性能
  2. FID (First Input Delay): 首次输入延迟

    • 目标: < 100ms
    • 衡量交互性
  3. CLS (Cumulative Layout Shift): 累积布局偏移

    • 目标: < 0.1
    • 衡量视觉稳定性

优化策略

1. 资源优化

图片优化

<!-- 使用现代图片格式 -->
<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="Description" loading="lazy">
</picture>

<!-- 响应式图片 -->
<img
  srcset="small.jpg 400w, medium.jpg 800w, large.jpg 1200w"
  sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
  src="medium.jpg"
  alt="Responsive image"
>

JavaScript 优化

// 代码分割
const HeavyComponent = lazy(() => import('./HeavyComponent'));

// 动态导入
button.addEventListener('click', async () => {
  const module = await import('./analytics.js');
  module.trackEvent('button-click');
});

// Tree shaking - 只导入需要的部分
import { debounce } from 'lodash-es'; // ✅
// import _ from 'lodash'; // ❌ 导入整个库

CSS 优化

/* 关键 CSS 内联 */
<style>
  /* 首屏必需的样式 */
  .hero { background: #000; color: #fff; }
</style>

/* 非关键 CSS 异步加载 */
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">

2. 网络优化

使用 CDN

<!-- Cloudflare CDN 示例 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>

HTTP/2 和 HTTP/3

  • 多路复用
  • 服务器推送
  • 头部压缩

缓存策略

// Service Worker 缓存
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      return response || fetch(event.request);
    })
  );
});
# Nginx 缓存配置
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

3. 渲染优化

虚拟滚动

// React 虚拟列表示例
import { FixedSizeList } from 'react-window';

function VirtualList({ items }) {
  return (
    <FixedSizeList
      height={600}
      itemCount={items.length}
      itemSize={50}
      width="100%"
    >
      {({ index, style }) => (
        <div style={style}>{items[index]}</div>
      )}
    </FixedSizeList>
  );
}

防抖和节流

// 防抖 - 等待用户停止输入
const debounce = (fn, delay) => {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  };
};

// 节流 - 限制执行频率
const throttle = (fn, limit) => {
  let inThrottle;
  return (...args) => {
    if (!inThrottle) {
      fn(...args);
      inThrottle = true;
      setTimeout(() => inThrottle = false, limit);
    }
  };
};

// 使用示例
const handleScroll = throttle(() => {
  console.log('Scrolling...');
}, 200);

const handleSearch = debounce((query) => {
  searchAPI(query);
}, 300);

避免布局抖动

// ❌ 强制同步布局
for (let i = 0; i < elements.length; i++) {
  const height = elements[i].offsetHeight; // 读
  elements[i].style.height = height + 10 + 'px'; // 写
}

// ✅ 批量读写
const heights = elements.map(el => el.offsetHeight); // 批量读
elements.forEach((el, i) => {
  el.style.height = heights[i] + 10 + 'px'; // 批量写
});

4. 预加载策略

<!-- DNS 预解析 -->
<link rel="dns-prefetch" href="https://api.example.com">

<!-- 预连接 -->
<link rel="preconnect" href="https://fonts.googleapis.com">

<!-- 预加载关键资源 -->
<link rel="preload" href="main.js" as="script">
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

<!-- 预获取下一页资源 -->
<link rel="prefetch" href="/next-page.html">

5. 字体优化

@font-face {
  font-family: 'CustomFont';
  src: url('font.woff2') format('woff2');
  font-display: swap; /* 避免不可见文本 */
}

/* 子集化字体 */
@font-face {
  font-family: 'CustomFont';
  src: url('font-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF; /* 只包含拉丁字符 */
}

监控和测试

性能测试工具

  1. Lighthouse: Chrome DevTools 集成
  2. WebPageTest: 详细的瀑布图分析
  3. Chrome DevTools Performance: 运行时性能分析

持续监控

// Web Vitals 监控
import { getCLS, getFID, getLCP } from 'web-vitals';

function sendToAnalytics(metric) {
  fetch('/analytics', {
    method: 'POST',
    body: JSON.stringify(metric),
  });
}

getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getLCP(sendToAnalytics);

Real User Monitoring (RUM)

// 使用 Performance API
window.addEventListener('load', () => {
  const perfData = performance.getEntriesByType('navigation')[0];

  console.log('DNS 查询:', perfData.domainLookupEnd - perfData.domainLookupStart);
  console.log('TCP 连接:', perfData.connectEnd - perfData.connectStart);
  console.log('请求响应:', perfData.responseEnd - perfData.requestStart);
  console.log('DOM 解析:', perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart);
});

优化检查清单

  • 启用 gzip/brotli 压缩
  • 图片懒加载
  • 代码分割和按需加载
  • 使用 CDN
  • 设置合理的缓存策略
  • 优化关键渲染路径
  • 减少第三方脚本
  • 使用 HTTP/2 或 HTTP/3
  • 实现 Service Worker
  • 监控 Core Web Vitals

实际案例

我最近优化了一个电商网站:

优化前:

  • LCP: 4.2s
  • FID: 180ms
  • CLS: 0.25

优化后:

  • LCP: 1.8s (-57%)
  • FID: 45ms (-75%)
  • CLS: 0.05 (-80%)

主要措施:

  1. 图片 WebP 格式 + CDN
  2. 代码分割,首屏 JS 减少 60%
  3. 实现虚拟滚动
  4. 优化字体加载策略

结果:

  • 页面加载速度提升 65%
  • 转化率提升 23%
  • SEO 排名上升

总结

性能优化是一个持续的过程,需要:

  1. 测量: 使用工具定期测试
  2. 分析: 找出瓶颈所在
  3. 优化: 逐步改进
  4. 监控: 持续跟踪指标

记住:优化要基于数据,不要过早优化!

想了解更多性能优化技巧?关注我的博客,我会持续分享实战经验。