核心理念

渐进式性能监控基于分层体验阶段化加载的思想,将应用的生命周期分解为多个关键阶段,为每个阶段建立独立的监控指标,从而全面反映用户体验的递进过程。

关键监控阶段与指标

1. 核心内容加载阶段

目标:监控用户感知到”内容已加载”的关键时刻

// 标记核心内容加载
class CoreContentMetrics {
  constructor() {
    this.observedElements = new Set();
  }
  
  // 监控关键内容元素可见性
  observeCriticalElements() {
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const element = entry.target;
          const metric = {
            type: 'critical_element_visible',
            element: element.tagName,
            id: element.id || 'unknown',
            timestamp: Date.now(),
            timeToVisible: performance.now()
          };
          
          this.reportMetric(metric);
          observer.unobserve(element);
        }
      });
    }, { threshold: 0.1 });
    
    // 观察关键内容元素
    document.querySelectorAll('[data-critical]').forEach(el => {
      observer.observe(el);
    });
  }
  
  // 标记核心内容完成
  markCoreContentLoaded() {
    performance.mark('core_content_loaded');
    
    // 计算核心内容加载时间
    const navStart = performance.getEntriesByType('navigation')[0]?.fetchStart || 0;
    const coreContentTime = performance.now() - navStart;
    
    this.reportMetric({
      type: 'core_content_complete',
      duration: coreContentTime,
      timestamp: Date.now()
    });
  }
}

2. 视觉稳定阶段

目标:监控布局偏移和视觉稳定性

class VisualStabilityMetrics {
  constructor() {
    this.cls = 0;
    this.clsObserver = null;
  }
  
  // 监控累积布局偏移 (CLS)
  monitorLayoutShifts() {
    let sessionValue = 0;
    let sessionEntries = [];
    
    this.clsObserver = new PerformanceObserver((list) => {
      list.getEntries().forEach(entry => {
        // 只计算没有用户输入的布局偏移
        if (!entry.hadRecentInput) {
          sessionEntries.push(entry);
          sessionValue += entry.value;
          
          this.reportMetric({
            type: 'layout_shift',
            value: entry.value,
            cumulative: sessionValue,
            element: entry.sources?.[0]?.node?.toString() || 'unknown'
          });
        }
      });
    });
    
    this.clsObserver.observe({ 
      type: 'layout-shift', 
      buffered: true 
    });
    
    // 页面隐藏时报告最终 CLS
    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'hidden') {
        this.reportMetric({
          type: 'final_cls',
          value: sessionValue,
          entries: sessionEntries.length
        });
      }
    });
  }
  
  // 监控图片加载导致的布局偏移
  monitorImageLoading() {
    const images = document.querySelectorAll('img');
    images.forEach(img => {
      if (!img.complete) {
        img.addEventListener('load', () => {
          this.checkLayoutImpact(img);
        });
      }
    });
  }
}

3. 交互准备阶段

目标:监控应用何时变得可交互

class InteractionReadinessMetrics {
  constructor() {
    this.longTasks = [];
    this.firstInputDelay = null;
  }
  
  // 监控长任务
  monitorLongTasks() {
    const observer = new PerformanceObserver((list) => {
      list.getEntries().forEach(entry => {
        this.longTasks.push(entry);
        
        this.reportMetric({
          type: 'long_task',
          duration: entry.duration,
          startTime: entry.startTime,
          context: entry.attribution?.[0]?.containerType || 'unknown'
        });
      });
    });
    
    observer.observe({ 
      entryTypes: ['longtask'] 
    });
  }
  
  // 监控首次输入延迟 (FID)
  monitorFirstInput() {
    const observer = new PerformanceObserver((list) => {
      list.getEntries().forEach(entry => {
        if (!this.firstInputDelay) {
          this.firstInputDelay = entry;
          
          this.reportMetric({
            type: 'first_input_delay',
            delay: entry.processingStart - entry.startTime,
            duration: entry.duration,
            interactionType: entry.name
          });
        }
      });
    });
    
    observer.observe({ 
      type: 'first-input', 
      buffered: true 
    });
  }
  
  // 计算可交互时间 (TTI)
  calculateTimeToInteractive() {
    const longTaskThreshold = 50; // ms
    const quietWindow = 5000; // 5 seconds
    
    let lastLongTaskEnd = 0;
    let tti = null;
    
    this.longTasks.forEach(task => {
      if (task.duration > longTaskThreshold) {
        lastLongTaskEnd = Math.max(lastLongTaskEnd, task.startTime + task.duration);
      }
    });
    
    if (lastLongTaskEnd > 0) {
      tti = lastLongTaskEnd + quietWindow;
    }
    
    return tti;
  }
}

4. 增强功能加载阶段

目标:监控非关键资源和功能的加载情况

class EnhancementMetrics {
  constructor() {
    this.enhancements = new Map();
  }
  
  // 监控代码分割组件的加载
  monitorCodeSplitting() {
    const originalImport = window.import;
    
    window.import = function(chunkName) {
      const startTime = performance.now();
      
      return originalImport.apply(this, arguments)
        .then(module => {
          const loadTime = performance.now() - startTime;
          
          this.reportMetric({
            type: 'chunk_loaded',
            name: chunkName,
            duration: loadTime,
            size: this.estimateChunkSize(module),
            timestamp: Date.now()
          });
          
          return module;
        })
        .catch(error => {
          this.reportMetric({
            type: 'chunk_load_error',
            name: chunkName,
            error: error.message,
            timestamp: Date.now()
          });
          
          throw error;
        });
    };
  }
  
  // 监控第三方脚本加载
  monitorThirdPartyResources() {
    const observer = new PerformanceObserver((list) => {
      list.getEntries().forEach(entry => {
        if (this.isThirdParty(entry.name)) {
          this.reportMetric({
            type: 'third_party_resource',
            name: this.extractDomain(entry.name),
            duration: entry.duration,
            size: entry.transferSize,
            cached: entry.transferSize === 0
          });
        }
      });
    });
    
    observer.observe({ 
      entryTypes: ['resource'] 
    });
  }
  
  // 监控组件级渲染性能
  monitorComponentRender(componentName) {
    const startMark = `${componentName}_render_start`;
    const endMark = `${componentName}_render_end`;
    
    performance.mark(startMark);
    
    return {
      end: () => {
        performance.mark(endMark);
        
        const measure = performance.measure(
          `${componentName}_render`,
          startMark,
          endMark
        );
        
        this.reportMetric({
          type: 'component_render',
          name: componentName,
          duration: measure.duration,
          timestamp: Date.now()
        });
      }
    };
  }
}

5. 运行时性能阶段

目标:监控应用运行时的性能表现

class RuntimePerformanceMetrics {
  constructor() {
    this.fps = 0;
    this.frameCount = 0;
    this.lastTime = performance.now();
  }
  
  // 监控帧率 (FPS)
  monitorFPS() {
    const calculateFPS = (now) => {
      this.frameCount++;
      
      if (now >= this.lastTime + 1000) {
        this.fps = Math.round((this.frameCount * 1000) / (now - this.lastTime));
        
        this.reportMetric({
          type: 'fps',
          value: this.fps,
          timestamp: now
        });
        
        this.frameCount = 0;
        this.lastTime = now;
      }
      
      requestAnimationFrame(calculateFPS);
    };
    
    requestAnimationFrame(calculateFPS);
  }
  
  // 监控内存使用
  monitorMemory() {
    if (performance.memory) {
      setInterval(() => {
        const memory = performance.memory;
        
        this.reportMetric({
          type: 'memory_usage',
          used: memory.usedJSHeapSize,
          total: memory.totalJSHeapSize,
          limit: memory.jsHeapSizeLimit,
          timestamp: Date.now()
        });
      }, 30000); // 每30秒报告一次
    }
  }
  
  // 监控网络状态变化
  monitorNetworkConditions() {
    if (navigator.connection) {
      const connection = navigator.connection;
      
      connection.addEventListener('change', () => {
        this.reportMetric({
          type: 'network_change',
          effectiveType: connection.effectiveType,
          downlink: connection.downlink,
          rtt: connection.rtt,
          timestamp: Date.now()
        });
      });
    }
  }
}

完整的监控系统集成

class ProgressivePerformanceMonitor {
  constructor() {
    this.metrics = [];
    this.reportUrl = '/api/performance-metrics';
    
    // 初始化各阶段监控
    this.coreMetrics = new CoreContentMetrics();
    this.visualMetrics = new VisualStabilityMetrics();
    this.interactionMetrics = new InteractionReadinessMetrics();
    this.enhancementMetrics = new EnhancementMetrics();
    this.runtimeMetrics = new RuntimePerformanceMetrics();
    
    this.setupGlobalErrorHandling();
  }
  
  // 启动所有监控
  start() {
    // 核心内容监控
    this.coreMetrics.observeCriticalElements();
    
    // 视觉稳定性监控
    this.visualMetrics.monitorLayoutShifts();
    this.visualMetrics.monitorImageLoading();
    
    // 交互准备监控
    this.interactionMetrics.monitorLongTasks();
    this.interactionMetrics.monitorFirstInput();
    
    // 增强功能监控
    this.enhancementMetrics.monitorCodeSplitting();
    this.enhancementMetrics.monitorThirdPartyResources();
    
    // 运行时监控
    this.runtimeMetrics.monitorFPS();
    this.runtimeMetrics.monitorMemory();
    this.runtimeMetrics.monitorNetworkConditions();
    
    // 标记各阶段完成
    this.markProgressivePhases();
  }
  
  // 标记渐进式阶段完成
  markProgressivePhases() {
    window.addEventListener('load', () => {
      this.coreMetrics.markCoreContentLoaded();
      
      // 延迟标记增强完成,等待关键用户交互准备就绪
      setTimeout(() => {
        this.reportMetric({
          type: 'enhancements_ready',
          timestamp: Date.now(),
          tti: this.interactionMetrics.calculateTimeToInteractive()
        });
      }, 1000);
    });
  }
  
  // 报告指标
  reportMetric(metric) {
    // 添加上下文信息
    const enrichedMetric = {
      ...metric,
      sessionId: this.getSessionId(),
      url: window.location.href,
      userAgent: navigator.userAgent,
      timestamp: metric.timestamp || Date.now()
    };
    
    this.metrics.push(enrichedMetric);
    
    // 批量报告
    if (this.metrics.length >= 10) {
      this.flushMetrics();
    }
  }
  
  // 批量发送指标
  flushMetrics() {
    if (this.metrics.length === 0) return;
    
    const metricsToSend = [...this.metrics];
    this.metrics = [];
    
    // 使用 sendBeacon 确保在页面卸载时也能发送
    if (navigator.sendBeacon) {
      navigator.sendBeacon(
        this.reportUrl, 
        JSON.stringify(metricsToSend)
      );
    } else {
      // 回退到 fetch
      fetch(this.reportUrl, {
        method: 'POST',
        body: JSON.stringify(metricsToSend),
        keepalive: true
      });
    }
  }
  
  // 设置全局错误处理
  setupGlobalErrorHandling() {
    window.addEventListener('error', (event) => {
      this.reportMetric({
        type: 'global_error',
        message: event.message,
        filename: event.filename,
        lineno: event.lineno,
        colno: event.colno,
        error: event.error?.toString()
      });
    });
    
    window.addEventListener('unhandledrejection', (event) => {
      this.reportMetric({
        type: 'unhandled_rejection',
        reason: event.reason?.toString()
      });
    });
  }
  
  getSessionId() {
    if (!this.sessionId) {
      this.sessionId = 'session_' + Math.random().toString(36).substr(2, 9);
    }
    return this.sessionId;
  }
}
 
// 使用示例
const monitor = new ProgressivePerformanceMonitor();
monitor.start();
 
// 在页面卸载前刷新所有指标
window.addEventListener('beforeunload', () => {
  monitor.flushMetrics();
});

监控数据分析与告警

class PerformanceAnalytics {
  constructor() {
    this.thresholds = {
      core_content: 3000,      // 3秒
      first_paint: 2000,       // 2秒
      first_input_delay: 100,  // 100ms
      layout_shift: 0.1,       // CLS 阈值
      long_task: 50,           // 50ms
      fps: 30                  // 30帧
    };
  }
  
  // 分析性能数据并生成告警
  analyzeMetrics(metrics) {
    const alerts = [];
    
    metrics.forEach(metric => {
      switch (metric.type) {
        case 'core_content_complete':
          if (metric.duration > this.thresholds.core_content) {
            alerts.push(this.createAlert('slow_core_content', metric));
          }
          break;
          
        case 'first_input_delay':
          if (metric.delay > this.thresholds.first_input_delay) {
            alerts.push(this.createAlert('high_input_delay', metric));
          }
          break;
          
        case 'layout_shift':
          if (metric.cumulative > this.thresholds.layout_shift) {
            alerts.push(this.createAlert('high_layout_shift', metric));
          }
          break;
          
        case 'long_task':
          if (metric.duration > this.thresholds.long_task) {
            alerts.push(this.createAlert('long_task_detected', metric));
          }
          break;
          
        case 'fps':
          if (metric.value < this.thresholds.fps) {
            alerts.push(this.createAlert('low_fps', metric));
          }
          break;
      }
    });
    
    return alerts;
  }
  
  createAlert(type, metric) {
    return {
      type,
      severity: this.getAlertSeverity(type),
      metric,
      timestamp: Date.now(),
      message: this.getAlertMessage(type, metric)
    };
  }
  
  getAlertSeverity(alertType) {
    const severityMap = {
      'slow_core_content': 'high',
      'high_input_delay': 'medium', 
      'high_layout_shift': 'medium',
      'long_task_detected': 'low',
      'low_fps': 'medium'
    };
    
    return severityMap[alertType] || 'low';
  }
}

总结

渐进式性能监控的核心价值在于:

  1. 分层监控:对应渐进式加载的每个阶段,提供精准的性能洞察
  2. 用户体验导向:关注用户真实感知的指标,而非单纯的技术指标
  3. 上下文丰富:结合业务场景,理解不同功能对用户的价值差异
  4. 主动预警:基于阈值分析,在问题影响用户前发现并解决
  5. 持续优化:为性能优化提供数据支撑和效果验证

这种监控方式确保了我们在追求功能丰富性的同时,始终保持对用户体验的高度关注,真正实现了”渐进增强”的性能维度实践。