Skip to content

前端监控是确保应用性能和用户体验的关键,主要涵盖以下核心指标,通常分为几个维度:


一、性能指标(Performance)

  1. 首次内容绘制 (FCP - First Contentful Paint)
    • 浏览器首次渲染任何文本、图片或非空白 Canvas/SVG 的时间。
    • 目标:< 1.8 秒(良好)
js
const getFCP = () => {
  // 1. 使用 PerformanceObserver 监听 paint 类型条目
  const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      if (entry.name === 'first-contentful-paint') {
        // 2. 获取 FCP 时间(单位:毫秒)
        const fcp = entry.startTime;
        console.log('FCP:', fcp);
        
        // 3. 上报数据(示例)
        sendToAnalytics({ metric: 'FCP', value: fcp });
        
        // 4. 停止监听
        observer.disconnect();
        break;
      }
    }
  });

  // 5. 开始监听 paint 类型的性能条目
  observer.observe({ type: 'paint', buffered: true });
};

// 调用函数开始采集
getFCP();
  1. 最大内容绘制 (LCP - Largest Contentful Paint)
    • 视口中最大可见元素(如图片、标题文本块)的渲染时间。
    • 目标:< 2.5 秒(良好)
js
const getLCP = () => {
  let maxLcpValue = 0;
  const lcpEntries = [];

  // 1. 创建观察者
  const observer = new PerformanceObserver((list) => {
    const entries = list.getEntries();
    entries.forEach(entry => {
      // 2. 记录所有 LCP 候选元素
      lcpEntries.push(entry);
      
      // 3. 更新最大 LCP 值(取 renderTime 或 loadTime)
      const time = entry.renderTime || entry.loadTime;
      if (time > maxLcpValue) {
        maxLcpValue = time;
      }
    });
  });

  // 4. 开始监听 LCP 条目
  observer.observe({ type: 'largest-contentful-paint', buffered: true });

  // 5. 页面加载完成时确定最终 LCP
  window.addEventListener('load', () => {
    // 延迟确保捕获所有元素
    setTimeout(() => {
      observer.disconnect();
      
      // 6. 取最后一个有效条目作为最终 LCP(根据规范)
      const finalEntry = lcpEntries[lcpEntries.length - 1];
      const lcp = finalEntry?.renderTime || maxLcpValue;
      
      console.log('LCP:', lcp);
      sendToAnalytics({ metric: 'LCP', value: lcp });
    }, 0);
  });

  // 7. 用户交互后停止记录(规范要求)
  ['click', 'keydown', 'scroll'].forEach(event => {
    window.addEventListener(event, () => observer.disconnect(), { once: true });
  });
};

getLCP();
  1. 首次输入延迟 (FID - First Input Delay)
    • 用户首次交互(点击、输入等)到浏览器实际响应的时间差。
    • 目标:< 100 毫秒(良好)
js
const getFID = () => {
  // 1. 记录首次交互时间
  let firstInteractionTime = performance.now();
  let hasReported = false;

  // 2. 监听首次输入事件
  const listener = (event) => {
    // 3. 跳过非用户主动交互(如滚动)
    if (event.cancelable) {
      const delay = event.processingStart - event.startTime;
      
      console.log('FID:', delay);
      sendToAnalytics({ metric: 'FID', value: delay });
      
      // 4. 移除监听
      window.removeEventListener('mousedown', listener);
      window.removeEventListener('keydown', listener);
      hasReported = true;
    }
  };

  // 5. 通过 PerformanceObserver 捕获 first-input 条目
  const observer = new PerformanceObserver(list => {
    list.getEntries().forEach(entry => {
      if (entry.entryType === 'first-input' && !hasReported) {
        const delay = entry.processingStart - entry.startTime;
        console.log('FID (via Observer):', delay);
        sendToAnalytics({ metric: 'FID', value: delay });
        hasReported = true;
      }
    });
  });

  observer.observe({ type: 'first-input', buffered: true });
  
  // 6. 降级方案:手动监听事件
  window.addEventListener('mousedown', listener, { once: true, capture: true });
  window.addEventListener('keydown', listener, { once: true, capture: true });
};

getFID();****
  1. 累积布局偏移 (CLS - Cumulative Layout Shift)
    • 衡量页面渲染期间视觉稳定性(元素意外偏移的频率和幅度)。
    • 目标:< 0.1(良好)
js
const getCLS = () => {
  let sessionValue = 0;
  let sessionEntries = [];
  let clsValue = 0;

  // 1. 布局偏移监听器
  const observer = new PerformanceObserver((list) => {
    list.getEntries().forEach(entry => {
      // 2. 忽略用户操作后500ms内的偏移(规范要求)
      if (!entry.hadRecentInput) {
        const lastEntry = sessionEntries[sessionEntries.length - 1];
        
        // 3. 检查是否同一会话(1秒内连续偏移)
        if (sessionEntries.length === 0 || 
            entry.startTime - lastEntry.startTime < 1000) {
          sessionValue += entry.value;
        } else {
          sessionValue = entry.value;
          sessionEntries = [];
        }
        
        // 4. 记录当前条目
        sessionEntries.push(entry);
        
        // 5. 更新最大会话值
        if (sessionValue > clsValue) {
          clsValue = sessionValue;
        }
      }
    });
  });

  // 6. 开始监听布局偏移
  observer.observe({ type: 'layout-shift', buffered: true });

  // 7. 页面隐藏时上报最终CLS
  const reportCLS = () => {
    observer.disconnect();
    console.log('CLS:', clsValue);
    sendToAnalytics({ metric: 'CLS', value: clsValue });
  };

  // 8. 在页面卸载或隐藏时报告
  window.addEventListener('visibilitychange', () => {
    if (document.visibilityState === 'hidden') reportCLS();
  });
  window.addEventListener('pagehide', reportCLS);
};

getCLS();
  1. 首字节时间 (TTFB - Time to First Byte)

    • 从发起请求到收到服务器响应的第一个字节的时间,反映服务器响应速度。
  2. 页面完全加载时间 (Load Time)

    • 从导航开始到 window.onload 事件触发的时间。

二、 错误监控(Errors)

  1. JavaScript 运行时错误
    • 通过 window.onerroraddEventListener('error') 捕获的未处理异常。
  2. 资源加载失败
    • 图片、脚本、CSS 等加载失败(通过 addEventListener('error') 捕获)。
  3. Promise 未捕获异常
    • 通过 unhandledrejection 事件监控。
  4. 接口请求错误
    • HTTP 状态码(4xx/5xx)、网络超时等。

三、 用户行为与体验(UX)

  1. 页面浏览量(PV)与独立访客(UV)
  2. 用户交互路径
    • 按钮点击、表单提交、路由跳转等关键操作。
  3. 白屏率
    • 页面完全无内容渲染的比例。
  4. 卡顿率
    • 页面帧率(FPS)低于 60 帧/秒的持续时间占比。

四、 接口监控(API)

  1. 请求成功率
    • 成功响应(2xx/3xx)的请求比例。
  2. 请求耗时分布
    • P50、P90、P99 分位的接口响应时间。
  3. 慢请求比例
    • 超过设定阈值(如 2 秒)的请求占比。
  4. 错误类型分布
    • 4xx(客户端错误) vs 5xx(服务端错误)。

五、 资源性能(Assets)

  1. CDN 资源加载速度
    • JS、CSS、图片等静态资源的加载耗时。
  2. 资源缓存命中率
    • 利用浏览器缓存(memory-cache/disk-cache)的比例。

六、 业务自定义指标

  1. 关键流程转化率
    • 如注册、支付流程的完成率。
  2. 功能使用率
    • 特定功能模块的点击/使用频率。
  3. 用户停留时长
    • 页面或应用的单次使用时长。

监控工具示例

  • 开源方案:Sentry(错误监控)、Prometheus + Grafana(性能指标)、Elastic APM
  • 商业平台:Datadog、New Relic、阿里云 ARMS、腾讯云前端性能监控
  • 标准协议:使用 W3C Performance Timeline API 采集性能数据

关键实践建议

  1. 核心 Web 指标(Web Vitals)优先:聚焦 LCP、FID、CLS 三大用户体验指标。
  2. 错误聚合与告警:对高频错误实时告警,避免影响范围扩大。
  3. 用户会话追踪(Session Replay):复现用户操作路径,辅助定位问题。
  4. 性能采样与聚合:全量监控可能消耗性能,合理采样降低开销。

💡 监控的核心目标是 快速发现问题 → 定位根因 → 驱动优化。建议结合业务场景选择关键指标,避免过度监控。