Skip to content
On this page

性能监控

性能监控是确保 Web 应用持续高性能的关键实践。本指南将详细介绍如何实现全面的性能监控,包括前端性能指标、后端性能指标和用户行为监控。

Web 性能指标

Core Web Vitals

javascript
// Core Web Vitals 监控
class CoreWebVitalsMonitor {
  constructor() {
    this.metrics = {
      CLS: 0,    // Cumulative Layout Shift
      FID: 0,    // First Input Delay
      LCP: 0     // Largest Contentful Paint
    };
    
    this.observerCallbacks = [];
  }
  
  // 监控累积布局偏移 (CLS)
  measureCLS() {
    let clsValue = 0;
    let clsEntries = [];
    
    const clsObserver = new PerformanceObserver((entryList) => {
      for (const entry of entryList.getEntries()) {
        // 只计算非动画引起的布局偏移
        if (!entry.hadRecentInput) {
          clsValue += entry.value;
          clsEntries.push(entry);
        }
      }
      
      // 报告 CLS 值
      this.reportMetric('CLS', clsValue, clsEntries);
    });
    
    clsObserver.observe({ entryTypes: ['layout-shift'] });
  }
  
  // 监控首次输入延迟 (FID)
  measureFID() {
    const fidObserver = new PerformanceObserver((entryList) => {
      const firstInput = entryList.getEntries()[0];
      const fidValue = firstInput.processingStart - firstInput.startTime;
      
      this.reportMetric('FID', fidValue, firstInput);
    });
    
    fidObserver.observe({ entryTypes: ['first-input'] });
  }
  
  // 监控最大内容绘制 (LCP)
  measureLCP() {
    let lcpValue = 0;
    let lcpEntry = null;
    
    const lcpObserver = new PerformanceObserver((entryList) => {
      const entries = entryList.getEntries();
      const lastEntry = entries[entries.length - 1];
      
      lcpValue = lastEntry.startTime;
      lcpEntry = lastEntry;
      
      // 如果页面隐藏,报告最终的 LCP 值
      if (document.visibilityState === 'hidden') {
        this.reportMetric('LCP', lcpValue, lcpEntry);
      }
    });
    
    lcpObserver.observe({ entryTypes: ['largest-contentful-paint'] });
    
    // 页面隐藏时报告 LCP
    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'hidden' && lcpEntry) {
        this.reportMetric('LCP', lcpValue, lcpEntry);
      }
    });
  }
  
  // 监控首次内容绘制 (FCP)
  measureFCP() {
    const fcpObserver = new PerformanceObserver((entryList) => {
      const fcpEntry = entryList.getEntries()[0];
      this.reportMetric('FCP', fcpEntry.startTime, fcpEntry);
    });
    
    fcpObserver.observe({ entryTypes: ['paint'] });
  }
  
  // 监控首次绘制 (FP)
  measureFP() {
    const fpObserver = new PerformanceObserver((entryList) => {
      const fpEntry = entryList.getEntries()[0];
      this.reportMetric('FP', fpEntry.startTime, fpEntry);
    });
    
    fpObserver.observe({ entryTypes: ['paint'] });
  }
  
  // 报告性能指标
  reportMetric(name, value, entry) {
    const metric = {
      name,
      value,
      entry,
      timestamp: Date.now(),
      url: window.location.href
    };
    
    // 调用观察者回调
    this.observerCallbacks.forEach(callback => callback(metric));
    
    // 发送到分析服务
    this.sendToAnalytics(metric);
  }
  
  // 添加观察者
  addObserver(callback) {
    this.observerCallbacks.push(callback);
  }
  
  // 发送到分析服务
  sendToAnalytics(metric) {
    // 发送到后端分析服务
    if (navigator.sendBeacon) {
      navigator.sendBeacon('/api/performance', JSON.stringify(metric));
    } else {
      // 降级方案
      fetch('/api/performance', {
        method: 'POST',
        body: JSON.stringify(metric),
        keepalive: true
      });
    }
  }
  
  // 初始化所有监控
  init() {
    this.measureCLS();
    this.measureFID();
    this.measureLCP();
    this.measureFCP();
    this.measureFP();
  }
}

// 使用 Core Web Vitals 监控
const vitalsMonitor = new CoreWebVitalsMonitor();

// 添加自定义观察者
vitalsMonitor.addObserver((metric) => {
  console.log(`${metric.name}: ${metric.value}`);
  
  // 根据指标值触发优化
  if (metric.name === 'CLS' && metric.value > 0.1) {
    console.warn('Layout shift is too high:', metric.value);
  }
});

vitalsMonitor.init();

自定义性能指标

javascript
// 自定义性能指标监控
class CustomPerformanceMonitor {
  constructor() {
    this.metrics = new Map();
    this.timings = new Map();
  }
  
  // 记录自定义时间
  mark(name) {
    performance.mark(name);
  }
  
  // 测量自定义时间间隔
  measure(name, startMark, endMark = undefined) {
    if (!endMark) {
      endMark = `end-${name}`;
      performance.mark(endMark);
    }
    
    performance.measure(name, startMark, endMark);
    
    const measure = performance.getEntriesByName(name)[0];
    this.timings.set(name, measure.duration);
    
    return measure.duration;
  }
  
  // 记录组件渲染时间
  measureComponentRender(componentName, renderFunction) {
    const startMark = `render-${componentName}-start`;
    const endMark = `render-${componentName}-end`;
    
    performance.mark(startMark);
    
    const result = renderFunction();
    
    performance.mark(endMark);
    performance.measure(`render-${componentName}`, startMark, endMark);
    
    const measure = performance.getEntriesByName(`render-${componentName}`)[0];
    this.reportMetric('ComponentRenderTime', measure.duration, { 
      componentName,
      duration: measure.duration 
    });
    
    return result;
  }
  
  // 监控 API 调用时间
  async measureApiCall(url, options = {}) {
    const startMark = `api-${Date.now()}`;
    performance.mark(startMark);
    
    try {
      const response = await fetch(url, options);
      const endMark = `api-${Date.now()}-end`;
      performance.mark(endMark);
      
      performance.measure(`api-${url}`, startMark, endMark);
      const measure = performance.getEntriesByName(`api-${url}`)[0];
      
      this.reportMetric('ApiCallTime', measure.duration, {
        url,
        method: options.method || 'GET',
        status: response.status,
        duration: measure.duration
      });
      
      return response;
    } catch (error) {
      const endMark = `api-${Date.now()}-end`;
      performance.mark(endMark);
      
      performance.measure(`api-${url}`, startMark, endMark);
      const measure = performance.getEntriesByName(`api-${url}`)[0];
      
      this.reportMetric('ApiCallError', measure.duration, {
        url,
        method: options.method || 'GET',
        error: error.message,
        duration: measure.duration
      });
      
      throw error;
    }
  }
  
  // 监控资源加载时间
  measureResourceLoad(url) {
    return new Promise((resolve, reject) => {
      const resourceObserver = new PerformanceObserver((list) => {
        for (const entry of list.getEntries()) {
          if (entry.name === url) {
            this.reportMetric('ResourceLoadTime', entry.duration, {
              url: entry.name,
              duration: entry.duration,
              entryType: entry.entryType
            });
            
            resolve(entry);
            resourceObserver.disconnect();
          }
        }
      });
      
      resourceObserver.observe({ entryTypes: ['resource'] });
      
      // 超时处理
      setTimeout(() => {
        reject(new Error(`Resource load timeout: ${url}`));
        resourceObserver.disconnect();
      }, 30000);
    });
  }
  
  // 报告指标
  reportMetric(name, value, details = {}) {
    const metric = {
      name,
      value,
      details,
      timestamp: Date.now(),
      userAgent: navigator.userAgent,
      url: window.location.href
    };
    
    // 存储指标
    if (!this.metrics.has(name)) {
      this.metrics.set(name, []);
    }
    this.metrics.get(name).push(metric);
    
    // 发送到分析服务
    this.sendToAnalytics(metric);
  }
  
  // 发送到分析服务
  sendToAnalytics(metric) {
    // 批量发送以减少请求数量
    if (!this.batch) {
      this.batch = [];
    }
    
    this.batch.push(metric);
    
    if (this.batch.length >= 10 || Date.now() - (this.lastSend || 0) > 5000) {
      this.sendBatch();
    }
  }
  
  sendBatch() {
    if (this.batch && this.batch.length > 0) {
      if (navigator.sendBeacon) {
        navigator.sendBeacon('/api/performance-batch', JSON.stringify(this.batch));
      } else {
        fetch('/api/performance-batch', {
          method: 'POST',
          body: JSON.stringify(this.batch),
          keepalive: true
        });
      }
      
      this.batch = [];
      this.lastSend = Date.now();
    }
  }
  
  // 获取指标统计
  getStats() {
    const stats = {};
    
    for (const [name, metrics] of this.metrics) {
      const values = metrics.map(m => m.value);
      stats[name] = {
        count: values.length,
        average: values.reduce((a, b) => a + b, 0) / values.length,
        min: Math.min(...values),
        max: Math.max(...values),
        p95: this.getPercentile(values, 95),
        p99: this.getPercentile(values, 99)
      };
    }
    
    return stats;
  }
  
  getPercentile(array, percentile) {
    const sorted = array.slice().sort((a, b) => a - b);
    const index = Math.ceil(percentile / 100 * sorted.length) - 1;
    return sorted[Math.max(0, index)];
  }
}

// 使用自定义性能监控
const customMonitor = new CustomPerformanceMonitor();

// 监控组件渲染
customMonitor.measureComponentRender('UserDashboard', () => {
  // 组件渲染逻辑
  return document.createElement('div');
});

// 监控 API 调用
customMonitor.measureApiCall('/api/users', { method: 'GET' });

后端性能监控

Node.js 性能监控

javascript
// Node.js 性能监控
const os = require('os');
const cluster = require('cluster');

class NodePerformanceMonitor {
  constructor(options = {}) {
    this.options = {
      interval: options.interval || 5000, // 5秒
      metricsEndpoint: options.metricsEndpoint || '/metrics',
      ...options
    };
    
    this.metrics = {
      cpu: [],
      memory: [],
      eventLoop: [],
      heap: []
    };
    
    this.startMonitoring();
  }
  
  // 开始监控
  startMonitoring() {
    this.cpuInterval = setInterval(() => {
      this.collectCpuMetrics();
    }, this.options.interval);
    
    this.memoryInterval = setInterval(() => {
      this.collectMemoryMetrics();
    }, this.options.interval);
    
    this.eventLoopInterval = setInterval(() => {
      this.collectEventLoopMetrics();
    }, this.options.interval);
  }
  
  // 收集 CPU 指标
  collectCpuMetrics() {
    const cpus = os.cpus();
    const cpuInfo = {
      count: cpus.length,
      model: cpus[0].model,
      speed: cpus[0].speed,
      usage: this.getCpuUsage(),
      timestamp: Date.now()
    };
    
    this.metrics.cpu.push(cpuInfo);
    this.sendMetric('cpu', cpuInfo);
    
    // 保持最近 100 个数据点
    if (this.metrics.cpu.length > 100) {
      this.metrics.cpu.shift();
    }
  }
  
  // 获取 CPU 使用率
  getCpuUsage() {
    const cpus = os.cpus();
    let user = 0, nice = 0, sys = 0, idle = 0, irq = 0;
    
    cpus.forEach(cpu => {
      user += cpu.times.user;
      nice += cpu.times.nice;
      sys += cpu.times.sys;
      idle += cpu.times.idle;
      irq += cpu.times.irq;
    });
    
    const total = user + nice + sys + idle + irq;
    const usage = (total - idle) / total * 100;
    
    return {
      usage: usage,
      breakdown: { user, nice, sys, idle, irq }
    };
  }
  
  // 收集内存指标
  collectMemoryMetrics() {
    const memoryInfo = {
      total: os.totalmem(),
      free: os.freemem(),
      used: os.totalmem() - os.freemem(),
      usage: (os.totalmem() - os.freemem()) / os.totalmem() * 100,
      rss: process.memoryUsage().rss,
      heapTotal: process.memoryUsage().heapTotal,
      heapUsed: process.memoryUsage().heapUsed,
      external: process.memoryUsage().external,
      arrayBuffers: process.memoryUsage().arrayBuffers,
      timestamp: Date.now()
    };
    
    this.metrics.memory.push(memoryInfo);
    this.sendMetric('memory', memoryInfo);
    
    if (this.metrics.memory.length > 100) {
      this.metrics.memory.shift();
    }
  }
  
  // 收集事件循环指标
  collectEventLoopMetrics() {
    const start = process.hrtime.bigint();
    
    setImmediate(() => {
      const end = process.hrtime.bigint();
      const delay = Number(end - start);
      
      const eventLoopInfo = {
        delay: delay,
        timestamp: Date.now()
      };
      
      this.metrics.eventLoop.push(eventLoopInfo);
      this.sendMetric('eventLoop', eventLoopInfo);
      
      if (this.metrics.eventLoop.length > 100) {
        this.metrics.eventLoop.shift();
      }
    });
  }
  
  // 发送指标
  sendMetric(type, data) {
    // 发送到监控服务
    console.log(`Performance Metric - ${type}:`, data);
    
    // 在实际应用中,这里会发送到监控服务
    // 例如:Prometheus、DataDog、New Relic 等
  }
  
  // 获取指标统计
  getStats() {
    return {
      cpu: this.getMetricStats(this.metrics.cpu),
      memory: this.getMetricStats(this.metrics.memory),
      eventLoop: this.getMetricStats(this.metrics.eventLoop)
    };
  }
  
  getMetricStats(metricArray) {
    if (metricArray.length === 0) return null;
    
    const values = metricArray.map(m => typeof m === 'object' ? m.usage || m.delay : m);
    const avg = values.reduce((a, b) => a + b, 0) / values.length;
    const min = Math.min(...values);
    const max = Math.max(...values);
    
    return { avg, min, max, count: values.length };
  }
  
  // 停止监控
  stop() {
    clearInterval(this.cpuInterval);
    clearInterval(this.memoryInterval);
    clearInterval(this.eventLoopInterval);
  }
}

// Express 中间件监控
const performanceMiddleware = (monitor) => {
  return (req, res, next) => {
    const start = process.hrtime.bigint();
    
    res.on('finish', () => {
      const duration = Number(process.hrtime.bigint() - start);
      
      // 记录请求性能
      const requestMetric = {
        method: req.method,
        url: req.url,
        statusCode: res.statusCode,
        duration: duration / 1000000, // 转换为毫秒
        timestamp: Date.now()
      };
      
      monitor.sendMetric('request', requestMetric);
    });
    
    next();
  };
};

// 使用示例
const app = require('express')();
const serverMonitor = new NodePerformanceMonitor();

app.use(performanceMiddleware(serverMonitor));

app.get('/api/data', (req, res) => {
  // 模拟一些处理时间
  setTimeout(() => {
    res.json({ data: 'sample' });
  }, 100);
});

用户体验监控

用户行为监控

javascript
// 用户行为监控
class UserExperienceMonitor {
  constructor(options = {}) {
    this.options = {
      trackClicks: options.trackClicks !== false,
      trackScrolls: options.trackScrolls !== false,
      trackFormInteractions: options.trackFormInteractions !== false,
      samplingRate: options.samplingRate || 1.0, // 100% 采样
      ...options
    };
    
    this.sessionId = this.generateSessionId();
    this.pageStartTime = Date.now();
    this.interactions = [];
    
    this.init();
  }
  
  init() {
    if (this.options.trackClicks) {
      this.trackClicks();
    }
    
    if (this.options.trackScrolls) {
      this.trackScrolls();
    }
    
    if (this.options.trackFormInteractions) {
      this.trackFormInteractions();
    }
    
    // 页面可见性变化
    document.addEventListener('visibilitychange', () => {
      this.trackVisibilityChange();
    });
    
    // 页面卸载
    window.addEventListener('beforeunload', () => {
      this.sendPageData();
    });
  }
  
  // 生成会话 ID
  generateSessionId() {
    return Math.random().toString(36).substr(2, 9) + Date.now().toString(36);
  }
  
  // 跟踪点击
  trackClicks() {
    document.addEventListener('click', (event) => {
      if (Math.random() > this.options.samplingRate) return;
      
      const clickData = {
        type: 'click',
        element: event.target.tagName,
        target: event.target.textContent?.substring(0, 50) || event.target.className,
        x: event.clientX,
        y: event.clientY,
        timestamp: Date.now(),
        sessionId: this.sessionId,
        url: window.location.href
      };
      
      this.interactions.push(clickData);
      this.sendInteractionData(clickData);
    });
  }
  
  // 跟踪滚动
  trackScrolls() {
    let scrollTimeout;
    
    const trackScroll = () => {
      const scrollData = {
        type: 'scroll',
        scrollTop: window.scrollY,
        scrollLeft: window.scrollX,
        maxScrollTop: document.body.scrollHeight - window.innerHeight,
        scrollPercent: (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100,
        timestamp: Date.now(),
        sessionId: this.sessionId
      };
      
      this.interactions.push(scrollData);
      this.sendInteractionData(scrollData);
    };
    
    window.addEventListener('scroll', () => {
      clearTimeout(scrollTimeout);
      scrollTimeout = setTimeout(trackScroll, 100);
    });
  }
  
  // 跟踪表单交互
  trackFormInteractions() {
    document.addEventListener('input', (event) => {
      if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA') {
        const formData = {
          type: 'form_input',
          fieldName: event.target.name || event.target.id,
          fieldType: event.target.type,
          valueLength: event.target.value.length,
          timestamp: Date.now(),
          sessionId: this.sessionId
        };
        
        this.interactions.push(formData);
        this.sendInteractionData(formData);
      }
    });
    
    document.addEventListener('focus', (event) => {
      if (event.target.tagName === 'INPUT' || event.target.tagName === 'TEXTAREA') {
        const focusData = {
          type: 'form_focus',
          fieldName: event.target.name || event.target.id,
          timestamp: Date.now(),
          sessionId: this.sessionId
        };
        
        this.interactions.push(focusData);
        this.sendInteractionData(focusData);
      }
    });
  }
  
  // 跟踪页面可见性变化
  trackVisibilityChange() {
    const visibilityData = {
      type: 'visibility_change',
      visibilityState: document.visibilityState,
      timestamp: Date.now(),
      sessionId: this.sessionId
    };
    
    this.interactions.push(visibilityData);
    this.sendInteractionData(visibilityData);
  }
  
  // 发送交互数据
  sendInteractionData(data) {
    // 使用 sendBeacon 确保数据发送
    if (navigator.sendBeacon) {
      navigator.sendBeacon('/api/user-interactions', JSON.stringify(data));
    } else {
      fetch('/api/user-interactions', {
        method: 'POST',
        body: JSON.stringify(data),
        keepalive: true
      });
    }
  }
  
  // 发送页面数据
  sendPageData() {
    const pageData = {
      sessionId: this.sessionId,
      pageUrl: window.location.href,
      pageLoadTime: Date.now() - this.pageStartTime,
      interactionCount: this.interactions.length,
      interactions: this.interactions,
      timestamp: Date.now(),
      userAgent: navigator.userAgent,
      screenResolution: `${screen.width}x${screen.height}`,
      viewportSize: `${window.innerWidth}x${window.innerHeight}`
    };
    
    if (navigator.sendBeacon) {
      navigator.sendBeacon('/api/page-data', JSON.stringify(pageData));
    } else {
      fetch('/api/page-data', {
        method: 'POST',
        body: JSON.stringify(pageData),
        keepalive: true
      });
    }
  }
  
  // 获取会话统计
  getSessionStats() {
    const clicks = this.interactions.filter(i => i.type === 'click').length;
    const scrolls = this.interactions.filter(i => i.type === 'scroll').length;
    const formInputs = this.interactions.filter(i => i.type === 'form_input').length;
    
    return {
      sessionId: this.sessionId,
      totalInteractions: this.interactions.length,
      clicks,
      scrolls,
      formInputs,
      pageLoadTime: Date.now() - this.pageStartTime,
      sessionDuration: Date.now() - this.pageStartTime
    };
  }
}

// 使用用户行为监控
const userMonitor = new UserExperienceMonitor({
  samplingRate: 0.1 // 10% 采样率
});

性能分析工具

性能分析报告

javascript
// 性能分析报告生成器
class PerformanceReportGenerator {
  constructor() {
    this.reports = [];
  }
  
  // 生成性能报告
  generateReport(data) {
    const report = {
      id: this.generateReportId(),
      timestamp: Date.now(),
      metrics: this.analyzeMetrics(data.metrics),
      recommendations: this.generateRecommendations(data.metrics),
      summary: this.generateSummary(data.metrics),
      metadata: {
        userAgent: data.userAgent || navigator.userAgent,
        url: data.url || window.location.href,
        environment: data.environment || 'production'
      }
    };
    
    this.reports.push(report);
    return report;
  }
  
  // 分析指标
  analyzeMetrics(metrics) {
    const analysis = {};
    
    // 分析加载时间
    if (metrics.loadTimes) {
      const loadTimes = metrics.loadTimes.map(m => m.value);
      analysis.loadTime = {
        average: loadTimes.reduce((a, b) => a + b, 0) / loadTimes.length,
        p95: this.getPercentile(loadTimes, 95),
        p99: this.getPercentile(loadTimes, 99),
        issues: this.identifyLoadTimeIssues(loadTimes)
      };
    }
    
    // 分析 CLS
    if (metrics.CLS) {
      const clsValues = metrics.CLS.map(m => m.value);
      analysis.cls = {
        average: clsValues.reduce((a, b) => a + b, 0) / clsValues.length,
        good: clsValues.filter(v => v < 0.1).length / clsValues.length * 100,
        needsImprovement: clsValues.filter(v => v >= 0.1 && v <= 0.25).length / clsValues.length * 100,
        poor: clsValues.filter(v => v > 0.25).length / clsValues.length * 100
      };
    }
    
    // 分析 FID
    if (metrics.FID) {
      const fidValues = metrics.FID.map(m => m.value);
      analysis.fid = {
        average: fidValues.reduce((a, b) => a + b, 0) / fidValues.length,
        good: fidValues.filter(v => v < 100).length / fidValues.length * 100,
        needsImprovement: fidValues.filter(v => v >= 100 && v <= 300).length / fidValues.length * 100,
        poor: fidValues.filter(v => v > 300).length / fidValues.length * 100
      };
    }
    
    // 分析 LCP
    if (metrics.LCP) {
      const lcpValues = metrics.LCP.map(m => m.value);
      analysis.lcp = {
        average: lcpValues.reduce((a, b) => a + b, 0) / lcpValues.length,
        good: lcpValues.filter(v => v < 2500).length / lcpValues.length * 100,
        needsImprovement: lcpValues.filter(v => v >= 2500 && v <= 4000).length / lcpValues.length * 100,
        poor: lcpValues.filter(v => v > 4000).length / lcpValues.length * 100
      };
    }
    
    return analysis;
  }
  
  // 识别加载时间问题
  identifyLoadTimeIssues(loadTimes) {
    const issues = [];
    
    if (this.getPercentile(loadTimes, 95) > 3000) {
      issues.push('95th percentile load time exceeds 3 seconds');
    }
    
    if (this.getPercentile(loadTimes, 50) > 2000) {
      issues.push('Median load time exceeds 2 seconds');
    }
    
    return issues;
  }
  
  // 生成建议
  generateRecommendations(metrics) {
    const recommendations = [];
    
    // CLS 建议
    if (metrics.CLS) {
      const clsValues = metrics.CLS.map(m => m.value);
      const avgCls = clsValues.reduce((a, b) => a + b, 0) / clsValues.length;
      
      if (avgCls > 0.25) {
        recommendations.push({
          priority: 'high',
          category: 'layout',
          description: 'Cumulative Layout Shift is too high',
          solution: 'Reserve space for images and ads, avoid inserting content without warning'
        });
      }
    }
    
    // FID 建议
    if (metrics.FID) {
      const fidValues = metrics.FID.map(m => m.value);
      const avgFid = fidValues.reduce((a, b) => a + b, 0) / fidValues.length;
      
      if (avgFid > 300) {
        recommendations.push({
          priority: 'high',
          category: 'interactivity',
          description: 'First Input Delay is too high',
          solution: 'Reduce JavaScript execution time, break up long tasks, use web workers'
        });
      }
    }
    
    // LCP 建议
    if (metrics.LCP) {
      const lcpValues = metrics.LCP.map(m => m.value);
      const avgLcp = lcpValues.reduce((a, b) => a + b, 0) / lcpValues.length;
      
      if (avgLcp > 4000) {
        recommendations.push({
          priority: 'high',
          category: 'loading',
          description: 'Largest Contentful Paint is too slow',
          solution: 'Optimize largest page elements, use resource hints, improve server response time'
        });
      }
    }
    
    return recommendations;
  }
  
  // 生成摘要
  generateSummary(metrics) {
    const summary = {
      overallScore: 0,
      categories: {}
    };
    
    // 计算各类别分数
    if (metrics.CLS) {
      const clsValues = metrics.CLS.map(m => m.value);
      const avgCls = clsValues.reduce((a, b) => a + b, 0) / clsValues.length;
      summary.categories.cls = avgCls < 0.1 ? 'good' : avgCls < 0.25 ? 'needs-improvement' : 'poor';
    }
    
    if (metrics.FID) {
      const fidValues = metrics.FID.map(m => m.value);
      const avgFid = fidValues.reduce((a, b) => a + b, 0) / fidValues.length;
      summary.categories.fid = avgFid < 100 ? 'good' : avgFid < 300 ? 'needs-improvement' : 'poor';
    }
    
    if (metrics.LCP) {
      const lcpValues = metrics.LCP.map(m => m.value);
      const avgLcp = lcpValues.reduce((a, b) => a + b, 0) / lcpValues.length;
      summary.categories.lcp = avgLcp < 2500 ? 'good' : avgLcp < 4000 ? 'needs-improvement' : 'poor';
    }
    
    // 计算整体分数
    const categories = Object.values(summary.categories);
    const goodCount = categories.filter(c => c === 'good').length;
    summary.overallScore = Math.round((goodCount / categories.length) * 100);
    
    return summary;
  }
  
  getPercentile(array, percentile) {
    const sorted = array.slice().sort((a, b) => a - b);
    const index = Math.ceil(percentile / 100 * sorted.length) - 1;
    return sorted[Math.max(0, index)];
  }
  
  generateReportId() {
    return `report_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }
  
  // 获取历史报告
  getReports() {
    return this.reports;
  }
}

// 使用性能报告生成器
const reportGenerator = new PerformanceReportGenerator();

// 示例:生成报告
const sampleData = {
  metrics: {
    CLS: [{ value: 0.15 }, { value: 0.22 }, { value: 0.08 }],
    FID: [{ value: 150 }, { value: 220 }, { value: 80 }],
    LCP: [{ value: 2800 }, { value: 3200 }, { value: 2100 }]
  }
};

const report = reportGenerator.generateReport(sampleData);
console.log('Performance Report:', report);

性能监控最佳实践

监控策略建议

javascript
// 性能监控配置
const PerformanceConfig = {
  // 采样配置
  sampling: {
    rate: 0.1, // 10% 采样率
    minPageViews: 1000, // 最小页面访问量才开始监控
    sessionTimeout: 30 * 60 * 1000 // 30分钟会话超时
  },
  
  // 阈值配置
  thresholds: {
    cls: { good: 0.1, poor: 0.25 },
    fid: { good: 100, poor: 300 },
    lcp: { good: 2500, poor: 4000 },
    fcp: { good: 1800, poor: 3000 }
  },
  
  // 监控指标
  metrics: [
    'CLS', 'FID', 'LCP', 'FCP', 'TTFB', 
    'domContentLoaded', 'pageLoadTime'
  ],
  
  // 数据保留策略
  retention: {
    realTime: 24 * 60 * 60 * 1000, // 24小时实时数据
    aggregated: 30 * 24 * 60 * 60 * 1000 // 30天聚合数据
  }
};

// 性能监控服务
class PerformanceMonitoringService {
  constructor(config = PerformanceConfig) {
    this.config = config;
    this.isEnabled = true;
    this.metricsBuffer = [];
    this.lastFlush = Date.now();
    
    this.init();
  }
  
  init() {
    // 初始化各种监控器
    this.coreVitalsMonitor = new CoreWebVitalsMonitor();
    this.customMonitor = new CustomPerformanceMonitor();
    this.userMonitor = new UserExperienceMonitor();
    
    // 设置定期刷新
    setInterval(() => {
      this.flushMetrics();
    }, 30000); // 每30秒刷新一次
  }
  
  // 添加指标到缓冲区
  addMetric(metric) {
    if (!this.isEnabled) return;
    
    this.metricsBuffer.push({
      ...metric,
      timestamp: Date.now(),
      sessionId: this.getSessionId()
    });
    
    // 如果缓冲区满了,立即刷新
    if (this.metricsBuffer.length >= 50) {
      this.flushMetrics();
    }
  }
  
  // 刷新指标到服务器
  flushMetrics() {
    if (this.metricsBuffer.length === 0) return;
    
    const batch = [...this.metricsBuffer];
    this.metricsBuffer = [];
    
    // 发送到服务器
    if (navigator.sendBeacon) {
      navigator.sendBeacon('/api/performance-batch', JSON.stringify(batch));
    } else {
      fetch('/api/performance-batch', {
        method: 'POST',
        body: JSON.stringify(batch),
        keepalive: true
      });
    }
  }
  
  // 获取会话 ID
  getSessionId() {
    if (!sessionStorage.getItem('perf_session_id')) {
      const sessionId = Math.random().toString(36).substr(2, 9) + Date.now().toString(36);
      sessionStorage.setItem('perf_session_id', sessionId);
    }
    return sessionStorage.getItem('perf_session_id');
  }
  
  // 检查是否应该采样
  shouldSample() {
    return Math.random() < this.config.sampling.rate;
  }
  
  // 启用监控
  enable() {
    this.isEnabled = true;
  }
  
  // 禁用监控
  disable() {
    this.isEnabled = false;
  }
  
  // 获取性能统计
  getStats() {
    return {
      bufferedMetrics: this.metricsBuffer.length,
      config: this.config,
      samplingRate: this.config.sampling.rate
    };
  }
}

// 初始化性能监控服务
const perfService = new PerformanceMonitoringService();

// 在页面加载完成后开始监控
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', () => {
    if (perfService.shouldSample()) {
      perfService.enable();
      console.log('Performance monitoring started');
    } else {
      console.log('Performance monitoring skipped due to sampling');
    }
  });
} else {
  if (perfService.shouldSample()) {
    perfService.enable();
  }
}

性能监控检查清单

  • [ ] 实施 Core Web Vitals 监控
  • [ ] 设置自定义性能指标
  • [ ] 监控后端性能指标
  • [ ] 跟踪用户行为和交互
  • [ ] 实施适当的采样策略
  • [ ] 设置性能阈值和警报
  • [ ] 生成性能分析报告
  • [ ] 实施数据保留策略
  • [ ] 确保监控不影响性能
  • [ ] 定期审查和优化监控策略

通过实施全面的性能监控,您可以及时发现性能问题并持续优化用户体验。