PerformanceObserver 必须在 HTML 解析开始前内联注册于 第一行,监听 'paint' 和 'navigation' 类型,禁用轮询与 DOM 操作,上报仅用 sendBeacon(),确保不拖慢首屏性能。

PerformanceObserver 必须在
最开头注册
监控脚本晚于 HTML 解析完成就等于没开——first-contentful-paint 和 domInteractive 这类关键时间点只触发一次,错过就永远漏掉。浏览器不会补发历史条目。
常见错误包括:DOMContentLoaded 里初始化、用 async 加载监控脚本、或把 new PerformanceObserver() 包在第三方 SDK 后面。
- 正确做法:内联一段 ≤1.5KB 的 IIFE 脚本,放在
第一行,直接调用.observe({ entryTypes: ['paint', 'navigation'] }) - 禁用
setInterval轮询performance.getEntriesByType()——主线程持续占用,部分 Android 会因此强制 GC - iOS Safari 对
performance.measure()支持不稳定,打点统一用Date.now()更稳妥
只监听 'paint' 和 'navigation' 两类 entryType
监听太多类型不是更全面,而是直接拖垮性能。全量上报 performance.getEntries() 会混入大量干扰项:字体加载、mark 打点、SPA 中频繁的 resource 条目,导致内存暴涨、上报体积激增、后端解析压力翻倍。
- 必须保留:
entryType === 'paint'(捕获first-paint/first-contentful-paint)、entryType === 'navigation'(提供domContentLoadedEventEnd、loadEventEnd、nextHopProtocol等字段) - SPA 场景要过滤伪 navigation:检查
entry.initiatorType === 'navigation',排除 fetch/XHR 触发的条目 - 废弃字段需兼容:
loadEventEnd在新版 Chromium 中可能为0,建议改用domContentLoadedEventEnd + loadEventStart推算
上报必须用 sendBeacon(),禁用 DOM 操作和 console.log
监控脚本自身就是资源,任何阻塞行为都会拖慢 HTML 解析流程。很多团队上线后发现 FCP 变差 80ms,最后定位到是监控回调里一个没删的 console.log —— DevTools 开启时会触发序列化开销。
- 上报唯一合规方式:
navigator.sendBeacon():异步、不阻塞卸载、保证送达 - 禁止在
observe回调中执行document.querySelector、getBoundingClientRect()或任何触发重排/重绘的操作 - 避免调用
performance.memory:该 API 在部分浏览器中会强制 GC,显著拉高主线程耗时 - 低端设备可降级:检测
navigator.hardwareConcurrency 时,跳过longtask监听,只保paint+navigation
HTML 解析阶段埋点不能依赖 document
任何在 中的 JS 都可能打断解析流。若监控脚本依赖 document 就初始化失败,比如调用 document.body 或 document.querySelector,会导致白屏或报错。
- 初始化逻辑必须不依赖 DOM:所有数据提取应在 entry 到达时直接读取并缓存,不要延迟到回调里再查
- 若需采集 TTFB 前的行为(如 DNS 查询失败),只能靠
PerformanceObserver监听navigation类型,而非读performance.timing - 内联脚本体积控制在 1.5KB 以内,移除 source map;避免
async/defer加载监控脚本,否则无法捕获首屏指标
真正难的不是加监控,而是让监控比它监控的对象更轻、更早、更克制——稍有不慎,它自己就成了性能瓶颈。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











