PerformanceObserver 性能条目类型(Entry Types)

149 阅读6分钟

PerformanceObserver 是 Web 性能监测的核心 API,通过指定 entryTypes 可以观察不同类型的性能指标。以下是所有支持的条目类型及其详细说明。


一、核心 Entry Types 列表

1.  'navigation'  — 页面导航性能

说明:测量主文档的导航和加载时间,提供完整的页面加载生命周期数据。

常用指标

  • entry.duration:总加载时间
  • entry.domContentLoadedEventEnd - entry.domContentLoadedEventStart:DOM 解析时间
  • entry.loadEventEnd - entry.loadEventStart:资源加载时间

使用场景:分析页面整体加载性能,计算 DNS、TCP、TTFB 等关键指标

2.  'resource'  — 资源加载性能

说明:测量页面上所有资源的加载时间,包括图片、CSS、JavaScript、XHR/Fetch 请求等。

关键属性

  • entry.name:资源 URL
  • entry.initiatorType:资源类型(img, script, link, xmlhttprequest, fetch
  • entry.duration:加载耗时
  • entry.decodedBodySize:资源大小

使用场景:定位慢资源、监控 CDN 效果、优化资源加载策略

3.  'paint'  — 渲染性能

说明:测量关键渲染时间点,主要用于 FCP(首次内容绘制)。

事件名称

  • entry.name === 'first-contentful-paint':FCP 时间

使用场景:Core Web Vitals 核心指标监控

4.  'largest-contentful-paint'  — 最大内容绘制

说明:作为独立条目类型提供更精确的 LCP 数据,包含详细的元素信息。

关键属性

  • entry.startTime:LCP 发生时间
  • entry.element:触发 LCP 的 DOM 元素
  • entry.url:图片资源的 URL(如适用)

使用场景:精准定位影响 LCP 的元素,优化最大内容加载

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(' LCP 详情:', {
      time: entry.startTime.toFixed(2) + 'ms',
      element: entry.element?.tagName,
      url: entry.url
    });
  }
});
observer.observe({ entryTypes: ['largest-contentful-paint'], buffered: true });

5.  'first-input'  — 首次输入延迟

说明:测量用户首次交互(点击、触摸、按键)到浏览器响应的延迟时间,是 Core Web Vitals 核心指标。

关键属性

  • entry.name:交互类型(click, pointerdown, keydown
  • entry.duration:总延迟时间
  • entry.processingStart / entry.processingEnd:事件处理时间

使用场景:评估用户对应用响应性的第一印象

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('首次交互延迟:', {
      type: entry.name,
      delay: entry.duration + 'ms'
    });
  }
});
observer.observe({ entryTypes: ['first-input'], buffered: true });

6.  'layout-shift'  — 布局偏移(CLS)

说明:测量页面元素的意外移动,用于计算 Cumulative Layout Shift (CLS)

关键属性

  • entry.value:单次布局偏移得分
  • entry.hadRecentInput:是否由用户输入触发(通常只关注 false 的情况)

使用场景:提升视觉稳定性,优化用户体验

7.  'event'  — 用户事件延迟

说明:测量所有用户交互事件(点击、键盘输入)的延迟时间。

关键属性

  • entry.name:事件类型(click, keydown 等)
  • entry.duration:事件处理耗时

使用场景:监控交互响应性,发现事件处理瓶颈

8.  'longtask'  — 长任务监控

说明:识别主线程上耗时超过 50 毫秒的任务,这些任务会阻塞用户交互。

关键属性

  • entry.duration:任务耗时
  • entry.attribution:导致长任务的代码信息

使用场景:发现 JavaScript 性能瓶颈,优化主线程执行

9.  'long-animation-frame'  — 长动画帧(LoAF)

说明新一代长任务监控,比 'longtask' 更细粒度,提供完整的调用栈和脚本归因。

关键属性

  • entry.duration:帧耗时
  • entry.scripts:详细的脚本执行信息数组

使用场景:精确诊断阻塞动画和交互的脚本

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('长动画帧:', {
      duration: entry.duration + 'ms',
      scripts: entry.scripts.map(s => ({
        source: s.sourceURL,
        function: s.sourceFunctionName,
        duration: s.duration + 'ms'
      }))
    });
  }
});
observer.observe({ entryTypes: ['long-animation-frame'], buffered: true });

10.  'element'  — 元素级性能

说明:观察特定 DOM 元素的渲染时间,用于更精确的 LCP 测量。

使用要求:元素需添加 elementtiming 属性

<img src="hero.jpg" elementtiming="hero-image" />

使用场景:监控关键业务元素的渲染性能

11.  'mark'  — 自定义时间戳标记

说明:通过 performance.mark() 创建命名时间戳,标记业务关键节点。

使用方式

performance.mark('user_login_start');
// ... 执行代码
performance.mark('user_login_end');

使用场景:自定义业务逻辑性能监控,如组件初始化时间、API 调用耗时等

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntriesByType('mark')) {
    console.log('标记点:', entry.name, entry.startTime + 'ms');
  }
});
observer.observe({ entryTypes: ['mark'], buffered: true });

12.  'measure'  — 自定义时间区间测量

说明:通过 performance.measure() 计算两个 mark 之间的时间差,是业务性能监控的黄金标准。

使用方式

performance.measure('login_duration', 'user_login_start', 'user_login_end');

使用场景:精确测量业务操作耗时,生成自定义性能指标

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntriesByType('measure')) {
    console.log('测量区间:', entry.name, entry.duration + 'ms');
  }
});
observer.observe({ entryTypes: ['measure'], buffered: true });

13.  'visibility-state'  — 页面可见性变化

说明:监控页面从可见到隐藏、从隐藏到可见的状态转换,对移动端性能优化至关重要。

关键属性

  • entry.prevState:之前的状态(visible, hidden, prerender
  • entry.currState:当前的状态

使用场景:页面隐藏时暂停非关键任务,节省 CPU 和电量

const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('可见性变化:', {
      from: entry.prevState,
      to: entry.currState
    });
    if (entry.currState === 'hidden') {
      pauseBackgroundTasks();
    }
  }
});
observer.observe({ entryTypes: ['visibility-state'], buffered: true });

二、浏览器兼容性说明

动态检查支持类型

通过 PerformanceObserver.supportedEntryTypes 获取当前浏览器支持的类型:

console.log(PerformanceObserver.supportedEntryTypes);
// 现代浏览器输出 (13):
// ['element', 'event', 'first-input', 'largest-contentful-paint', 
//  'layout-shift', 'long-animation-frame', 'longtask', 'mark', 
//  'measure', 'navigation', 'paint', 'resource', 'visibility-state']

注意:该属性是静态只读属性,返回数组reactnative.dev/docs/next/g…

兼容性差异

  • 现代浏览器 (Chrome 120+, Edge 120+):支持全部 13 种类型
  • Safari:支持基础类型,对新类型(如 long-animation-frame)支持较慢
  • Firefox:支持核心类型,部分实验性类型不支持
  • IE:完全不支持 PerformanceObserver

推荐做法

const supportedTypes = PerformanceObserver.supportedEntryTypes || [];
const desiredTypes = [
  'navigation', 'resource', 'paint', 'first-input', 'layout-shift',
  'longtask', 'event', 'largest-contentful-paint', 'long-animation-frame'
];
const entryTypes = desiredTypes.filter(type => supportedTypes.includes(type));

if (entryTypes.length > 0) {
  observer.observe({ entryTypes, buffered: true });
}

三、完整使用示例

监控多种性能指标

// 创建观察者实例
const observer = new PerformanceObserver((entryList) => {
  const entries = entryList.getEntries();
  
  entries.forEach(entry => {
    console.log(`类型: ${entry.entryType}, 名称: ${entry.name}, 耗时: ${entry.duration}ms`);
    
    // 根据类型分别处理
    switch(entry.entryType) {
      case 'navigation':
        console.log('页面加载完成:', entry.duration + 'ms');
        break;
      case 'resource':
        if (entry.duration > 200) {
          console.warn('慢资源:', entry.name);
        }
        break;
      case 'largest-contentful-paint':
        console.log('LCP:', entry.startTime.toFixed(2) + 'ms');
        break;
      case 'first-input':
        console.log('🖱️ 首次交互延迟:', entry.duration + 'ms');
        break;
      case 'layout-shift':
        if (!entry.hadRecentInput) {
          console.log('CLS 累积:', entry.value);
        }
        break;
      case 'long-animation-frame':
        console.error('长动画帧:', entry.duration + 'ms');
        break;
      case 'visibility-state':
        console.log('可见性变化:', entry.currState);
        break;
    }
  });
});

// 开始观察(推荐设置 buffered: true 获取历史数据)
observer.observe({
  entryTypes: [
    'navigation',
    'resource',
    'largest-contentful-paint',
    'first-input',
    'layout-shift',
    'long-animation-frame',
    'visibility-state'
  ],
  buffered: true
});

关键点

  • buffered: true :收集 observe() 调用之前已发生的性能条目,防止遗漏
  • disconnect() :不再需要时调用,释放资源

五、总结矩阵

#Entry Type主要指标典型阈值所属标准监控场景
1navigation页面加载时间< 3sNavigation Timing整体加载性能
2resource资源加载耗时< 200msResource Timing慢资源定位
3paintFCP< 1.8sPaint Timing首次渲染
4largest-contentful-paintLCP< 2.5sLCP API最大内容渲染
5first-inputFID< 100msEvent Timing首次交互响应
6layout-shiftCLS< 0.1Layout Instability视觉稳定性
7event交互延迟< 100msEvent Timing所有事件延迟
8longtask主线程阻塞> 50msLong Tasks API卡顿检测
9long-animation-frame长动画帧阻塞> 50msLoAF API精细化卡顿分析
10element元素渲染时间业务自定义Element Timing关键元素监控
11mark自定义时间戳-User Timing业务埋点
12measure自定义时间区间业务自定义User Timing区间测量
13visibility-state页面可见性变化-Page Visibility节能优化

通过合理组合这些 entry types,可以构建全面的前端性能监控体系,为优化提供数据支撑