Skip to content
On this page

性能优化基础概念

性能优化是提升Web应用程序速度、响应性和用户体验的关键过程。良好的性能不仅能提高用户满意度,还能改善SEO排名和业务指标。本章将介绍性能优化的基本概念、重要指标和优化策略。

性能的重要性

用户体验影响

性能对用户体验有着直接的影响:

  • 加载时间:页面加载时间每增加1秒,转化率可能下降7%
  • 响应速度:用户期望页面在3秒内加载完成
  • 交互流畅度:动画和交互应保持60fps的流畅度
  • 用户留存:性能提升可以显著提高用户留存率

业务影响

  • 转化率:Amazon发现页面加载时间每增加100毫秒,收入下降1%
  • SEO排名:Google将页面速度作为搜索排名因素
  • 运营成本:优化的代码和资源可以降低服务器成本
  • 品牌形象:快速响应的应用提升品牌信誉

关键性能指标(Core Web Vitals)

Google定义了三个关键的用户体验指标:

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

衡量加载性能,目标是在2.5秒内完成。

javascript
// 监测LCP
import { getLCP } from 'web-vitals';

getLCP(console.log);

2. 首次输入延迟(FID - First Input Delay)

衡量交互响应性,目标是小于100毫秒。

javascript
// 监测FID
import { getFID } from 'web-vitals';

getFID(console.log);

3. 累积布局偏移(CLS - Cumulative Layout Shift)

衡量视觉稳定性,目标是小于0.1。

javascript
// 监测CLS
import { getCLS } from 'web-vitals';

getCLS(console.log);

性能测量工具

1. Lighthouse

Google的开源自动化工具,用于改进网页质量。

bash
# 命令行使用
npx lighthouse https://example.com --output json --output-path report.json

2. Web Vitals库

轻量级库,用于测量核心Web指标。

javascript
import {
  getCLS,
  getFID,
  getFCP,
  getLCP,
  getTTFB
} from 'web-vitals';

// 发送性能数据到分析服务
function sendToAnalytics(metric) {
  const body = JSON.stringify(metric);
  const url = 'https://example.com/analytics';

  // 使用sendBeacon发送数据
  if (navigator.sendBeacon) {
    navigator.sendBeacon(url, body);
  } else {
    fetch(url, { body, method: 'POST', keepalive: true });
  }
}

getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);

3. Performance API

浏览器内置的性能测量工具。

javascript
// 测量特定操作的性能
function measureFunctionPerformance(fn, name) {
  performance.mark(`${name}-start`);
  
  const result = fn();
  
  performance.mark(`${name}-end`);
  performance.measure(name, `${name}-start`, `${name}-end`);
  
  const measure = performance.getEntriesByName(name)[0];
  console.log(`${name} took ${measure.duration} milliseconds`);
  
  return result;
}

// 获取性能数据
function getPerformanceData() {
  const perfData = performance.getEntriesByType('navigation')[0];
  return {
    dnsTime: perfData.domainLookupEnd - perfData.domainLookupStart,
    tcpTime: perfData.connectEnd - perfData.connectStart,
    requestTime: perfData.responseStart - perfData.requestStart,
    responseTime: perfData.responseEnd - perfData.responseStart,
    domLoadTime: perfData.domContentLoadedEventEnd - perfData.navigationStart
  };
}

性能优化策略

1. 资源优化

压缩和缩小

javascript
// Webpack配置示例
module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true, // 移除console语句
          },
        },
      }),
    ],
  },
};

图片优化

html
<!-- 响应式图片 -->
<picture>
  <source media="(min-width: 800px)" srcset="large.webp" type="image/webp">
  <source media="(min-width: 800px)" srcset="large.jpg" type="image/jpeg">
  <source srcset="small.webp" type="image/webp">
  <img src="small.jpg" alt="描述" loading="lazy">
</picture>

<!-- 使用srcset提供多种分辨率 -->
<img src="image-400.jpg"
     srcset="image-400.jpg 400w,
             image-800.jpg 800w,
             image-1200.jpg 1200w"
     sizes="(max-width: 600px) 400px,
            (max-width: 1000px) 800px,
            1200px"
     alt="响应式图片">

2. 代码分割和懒加载

javascript
// 动态导入实现代码分割
const loadModule = async () => {
  const { heavyFunction } = await import('./heavy-module');
  return heavyFunction();
};

// React中的懒加载组件
import { lazy, Suspense } from 'react';

const LazyComponent = lazy(() => import('./LazyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </Suspense>
  );
}

3. 缓存策略

javascript
// HTTP缓存头设置
app.use((req, res, next) => {
  // 静态资源长期缓存
  if (req.url.match(/\.(js|css|png|jpg|jpeg|gif|ico|svg)$/)) {
    res.setHeader('Cache-Control', 'public, max-age=31536000'); // 1年
  } else {
    // HTML文件不缓存
    res.setHeader('Cache-Control', 'no-cache');
  }
  next();
});

4. 预加载策略

html
<!-- 预加载关键资源 -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="hero-image.jpg" as="image">
<link rel="preload" href="critical.js" as="script">

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

<!-- DNS预获取 -->
<link rel="dns-prefetch" href="//fonts.googleapis.com">

前端性能优化

1. JavaScript优化

javascript
// 避免内存泄漏
class Component {
  constructor() {
    this.handleResize = this.handleResize.bind(this);
    window.addEventListener('resize', this.handleResize);
  }

  handleResize() {
    // 处理resize事件
  }

  destroy() {
    // 移除事件监听器
    window.removeEventListener('resize', this.handleResize);
  }
}

// 使用requestIdleCallback处理非关键任务
function nonCriticalTask() {
  if ('requestIdleCallback' in window) {
    requestIdleCallback(doWork);
  } else {
    setTimeout(doWork, 1);
  }
}

function doWork(deadline) {
  while (deadline.timeRemaining() > 0 && tasks.length > 0) {
    performTask();
  }
  if (tasks.length > 0) {
    requestIdleCallback(doWork);
  }
}

2. CSS优化

css
/* 避免复杂选择器 */
/* 不好的做法 */
div.container ul li span.highlighted {
  color: red;
}

/* 好的做法 */
.highlighted-text {
  color: red;
}

/* 使用transform和opacity进行动画 */
.animate-element {
  /* 避免改变layout或paint的属性 */
  transform: translateX(100px); /* 好 - 只影响composite */
  opacity: 0.5; /* 好 - 只影响composite */
}

/* 避免 */
.bad-animation {
  width: 200px; /* 不好 - 影响layout */
  height: 200px; /* 不好 - 影响layout */
  background-color: red; /* 不好 - 可能影响paint */
}

后端性能优化

1. 数据库查询优化

javascript
// 使用索引优化查询
// 在数据库中为经常查询的字段创建索引
// SELECT * FROM users WHERE email = 'user@example.com'; -- email字段应该有索引

// 避免N+1查询问题
const getUsersWithPosts = async () => {
  // 不好的做法 - N+1查询
  // const users = await User.findAll();
  // for (const user of users) {
  //   user.posts = await Post.findAll({ where: { userId: user.id }});
  // }

  // 好的做法 - 单次查询
  const users = await User.findAll({
    include: [{ model: Post }]
  });
  return users;
};

// 分页查询大数据集
const getUsersPaginated = async (page = 1, limit = 10) => {
  const offset = (page - 1) * limit;
  return await User.findAndCountAll({
    limit,
    offset,
    order: [['createdAt', 'DESC']]
  });
};

2. 缓存实现

javascript
// Redis缓存示例
const redis = require('redis');
const client = redis.createClient();

const getCachedData = async (key, fetchFunction) => {
  // 尝试从缓存获取
  const cached = await client.get(key);
  if (cached) {
    return JSON.parse(cached);
  }

  // 缓存未命中,从数据库获取
  const data = await fetchFunction();
  
  // 存储到缓存(1小时过期)
  await client.setex(key, 3600, JSON.stringify(data));
  
  return data;
};

// 使用示例
const getUser = async (id) => {
  return await getCachedData(
    `user:${id}`,
    () => User.findByPk(id)
  );
};

性能监控

1. 实时监控

javascript
// 性能监控类
class PerformanceMonitor {
  constructor() {
    this.metrics = new Map();
  }

  startTimer(name) {
    this.metrics.set(name, performance.now());
  }

  endTimer(name) {
    const start = this.metrics.get(name);
    if (start) {
      const duration = performance.now() - start;
      console.log(`${name} took ${duration.toFixed(2)} milliseconds`);
      this.metrics.delete(name);
      return duration;
    }
  }

  // 监控API调用性能
  async monitorAPICall(url, options = {}) {
    this.startTimer(`api-${url}`);
    
    try {
      const response = await fetch(url, options);
      const duration = this.endTimer(`api-${url}`);
      
      // 如果请求时间过长,记录警告
      if (duration > 1000) {
        console.warn(`Slow API call: ${url} took ${duration}ms`);
      }
      
      return response;
    } catch (error) {
      this.endTimer(`api-${url}`);
      throw error;
    }
  }
}

const perfMonitor = new PerformanceMonitor();

2. 性能预算

javascript
// 性能预算配置
const performanceBudget = {
  metrics: {
    lcp: 2500, // 2.5秒
    fid: 100,  // 100毫秒
    cls: 0.1,  // 0.1
    fcp: 1800, // 1.8秒
    ttfb: 200  // 200毫秒
  },
  resourceSizes: {
    javascript: 250 * 1024, // 250KB
    css: 50 * 1024,         // 50KB
    images: 1024 * 1024     // 1MB
  },
  resourceCounts: {
    requests: 50
  }
};

// 验证性能预算
function checkPerformanceBudget(metrics) {
  const violations = [];
  
  Object.keys(performanceBudget.metrics).forEach(key => {
    if (metrics[key] > performanceBudget.metrics[key]) {
      violations.push({
        metric: key,
        actual: metrics[key],
        budget: performanceBudget.metrics[key]
      });
    }
  });
  
  return violations;
}

性能优化检查清单

构建时优化

  • [ ] 启用代码压缩和缩小
  • [ ] 实现代码分割
  • [ ] 移除未使用的代码(Tree Shaking)
  • [ ] 使用长期缓存的文件名
  • [ ] 启用Gzip/Brotli压缩

运行时优化

  • [ ] 实现资源懒加载
  • [ ] 优化关键渲染路径
  • [ ] 使用适当的缓存策略
  • [ ] 优化图片和媒体资源
  • [ ] 减少HTTP请求数量
  • [ ] 使用CDN分发静态资源

监控和维护

  • [ ] 设置性能监控
  • [ ] 定期进行性能审计
  • [ ] 实施性能预算
  • [ ] 持续优化和测试

总结

性能优化是一个持续的过程,需要在开发、测试和生产环境中不断监控和改进。通过理解性能指标、采用合适的优化策略和工具,可以显著提升Web应用程序的性能和用户体验。在接下来的章节中,我们将深入探讨各种具体的性能优化技术和实践。