PerformanceObserver监听resource类型更优,因它实时捕获动态加载资源、不漏失败请求、避免主线程阻塞;而performance.getEntriesByType('resource')仅返回已完成资源、易致低端设备卡顿、无法区分资源类型且存在浏览器兼容性问题。

直接用 PerformanceObserver 监听 resource 类型,但必须限制粒度、过滤目标资源、避开低端设备——否则监控脚本自己就成了性能瓶颈。
为什么不能用 performance.getEntriesByType('resource') 一次性取全量
页面加载中,resource 条目可能轻松破百(尤其含字体、图片、第三方 SDK),在低端 Android 或 iPhone 6s 上调用该 API 会触发大量内存分配,拖慢主线程。更糟的是,它只返回已加载完成的资源,漏掉失败或被 cancel 的请求(比如 DNS 失败、预连接中断)。
- 首次调用需等所有资源加载完才返回数据,无法实时捕获加载中状态
- 不区分资源类型:你只想看
script和font,但它把每个favicon.ico也塞进来 - 部分浏览器(如旧版 Safari)对大量
resource条目做内部排序,耗时不可控
PerformanceObserver 监听 resource 的正确初始化时机
必须写在 最开头的内联 <script></script> 中,且不能依赖任何外部 JS 或 DOM。晚于 或用 async 加载,就会错过首屏关键资源(比如关键 CSS 的 link[rel="stylesheet"])。
- 注册代码要极简:
new PerformanceObserver(cb).observe({ entryTypes: ['resource'] }),别包 IIFE 或加 try/catch(除非你真需要捕获 observer 内部错误) - 回调里禁止同步发请求、禁止
document.querySelector、禁止修改 DOM;只做轻量判断 + 存入数组 - 若页面用 Webpack/Vite 构建,确保监控脚本不被打包进主 bundle,而是单独内联 —— 否则体积膨胀会延迟 HTML 解析
怎么过滤出真正关心的资源并避免误报
不是所有 resource 都值得上报。重点盯住影响首屏渲染和交互的几类:阻塞解析的 script、延迟样式应用的 stylesheet、卡住文本渲染的 font,以及常失败的 fetch 请求(通过 initiatorType 判断)。
立即学习“前端免费学习笔记(深入)”;
- 用
entry.initiatorType精准识别来源:'script'、'link'、'fetch'、'xmlhttprequest',排除'img'和'other'(后者常是 beacon 或埋点请求) - 用
entry.name做白名单匹配,例如只上报包含/main.或/fonts/的 URL,避免日志爆炸 - 检查
entry.duration === 0 && entry.transferSize === 0,这类大概率是缓存命中或 CORS 预检失败,需单独标记,不能混进“加载耗时”统计
卸载前如何安全上报 resource 数据而不丢失
sendBeacon() 是唯一可靠方式,但 resource 条目太多时,单次 beacon 可能超限(Chrome 限制约 64KB)。不能一股脑塞进去,得聚合压缩。
- 只保留必要字段:
name、initiatorType、duration、transferSize、nextHopProtocol,砍掉serverTiming和完整 URL 参数 - 按域名聚合:对同一
entry.name的前缀(如https://cdn.example.com/)统计平均duration和失败率,减少条目数 - 在
beforeunload回调里调用sendBeacon,且只发一次;重复调用无效,还可能被浏览器静默丢弃
最难的不是拿到 resource 数据,而是让监听本身不改变 resource 的加载行为——比如你在 observer 里不小心触发了 getComputedStyle,就可能强制重排,反而延长 FCP。真实环境里,90% 的 resource 监控失真,都源于监控逻辑比被监控对象更重。



















