直接用 PerformanceObserver 监听 resource 类型条目,结合动态阈值(p95+标准差)判断异步请求延时波动,触发非阻塞降级(如跳过非核心接口、启用缓存),并兼容旧环境保底埋点。

直接用 PerformanceObserver 监听 resource 类型条目,配合动态阈值判断和业务降级逻辑,就能实现对异步交互延时的实时监控与自动响应。核心不靠手动打点,而是依赖浏览器原生采集的完整网络阶段数据,既准又轻量。
捕获真实 fetch/XHR 请求耗时
浏览器对每个同源或带 Timing-Allow-Origin 响应头的 fetch/XHR 请求,都会自动生成一条 resource 类型性能条目。关键字段包括:
- duration:总耗时(从请求发起至响应体接收完毕)
- responseStart - requestStart:TTFB(首字节时间),反映后端处理能力
- responseEnd - responseStart:下载耗时,反映网络带宽与资源体积
- initiatorType === 'fetch' 或 'xmlhttprequest':精准过滤异步请求
建立波动感知的动态阈值
固定阈值(如 >2s 就降级)容易误触。推荐按分位统计最近 N 次同类请求的耗时,取 p95 作为当前基线,再叠加短期滑动窗口标准差:
- 每 10 条 fetch 条目更新一次 p95 基线(可存于内存 Map,按 URL 路径或业务标识分组)
- 若某次请求耗时 > 基线 × 1.8 或 > 基线 + 2×σ(σ 为近 10 次标准差),视为显著波动
- 避免单次毛刺干扰,要求连续 2 次触发才进入“波动态”
触发降级动作需解耦且可控
降级不是简单报错,而是有策略地切换行为。上报与执行都应异步、非阻塞:
- 在
requestIdleCallback或setTimeout(..., 0)中执行降级逻辑,不卡主线程 - 常见降级动作:跳过非核心接口调用、启用本地缓存兜底、隐藏加载骨架屏改显静态占位、切换简化版数据结构
- 记录降级原因(如 “fetch /api/user p95=842ms, 当前=1930ms”)并上报监控系统,用于事后归因
兼容旧环境的保底方案
IE 或部分 WebView 不支持 PerformanceObserver,需在统一请求封装层埋点:
- 所有 fetch 调用前记
const start = performance.now() - .then/.catch 中计算耗时,仅当满足波动条件时才触发降级回调
- 仍用
requestIdleCallback上报,避免影响渲染帧率 - 注意过滤掉
type === 'navigate'或重定向、缓存命中(transferSize === 0)等无效样本

















