直接用 performanceobserver 监听 longtask 是定位页面卡顿最直接轻量的方式,需在 head 内尽早初始化、启用 buffered、按时间桶聚合统计、过滤伪长任务,并结合用户操作打点精准归因。

直接用 PerformanceObserver 监听 longtask 类型,是定位页面卡顿最直接、最轻量的方式。它不依赖帧率计算,也不靠轮询采样,而是由浏览器在主线程被单个任务阻塞超 50ms 时主动推送原始数据——这正好对应人类可感知的响应延迟临界点。
必须在 head 最早位置初始化
长任务大量发生在页面加载初期:HTML 解析、首屏 JS 执行、关键组件挂载。如果 observer 在 DOMContentLoaded 之后才创建,会错过真实瓶颈。正确做法是把监听代码写在 内的内联 <script></script> 中,不加 defer 或 async,并前置兼容性判断:
if ('PerformanceObserver' in window && PerformanceObserver.supportedEntryTypes?.includes('longtask')) { ... }- 避免等第三方 SDK 加载完成再启动,否则监控存在盲区
- 启用
buffered: true可捕获 observer 创建前已发生的长任务(尤其对首屏关键路径很重要)
关注连续性,不止看单次耗时
一次 duration > 50 可能只是偶发;真正影响交互的是短时间内的密集阻塞。比如 3 秒内出现 3 次以上,用户就会明显感到卡顿。
- 用时间桶聚合:按
Math.floor(entry.startTime / 3000)分组,统计每 3 秒的长任务次数 - 过滤掉伪长任务:排除
name === "iframe"或 attribution 明确指向统计 SDK、广告脚本等内容 - 重点关注
entry.name === "self"且duration > 100的条目,它们大概率来自主文档业务逻辑
结合用户操作打点,快速定位问题场景
长任务本身不带函数名或堆栈,但和用户行为对齐后,就能大幅缩小排查范围。
- 在
click、scroll、input等事件前后插入performance.mark(),例如performance.mark('search-start') - 在 observer 回调中比对
entry.startTime是否紧邻这些标记点(如entry.startTime - performance.getEntriesByName('search-start')[0]?.startTime ) - 打开 Chrome DevTools → Performance 面板 → 录制复现流程,用火焰图查找对应时间戳附近的长 JS 块
生产环境需节流上报并带上下文
频繁上报不仅增加网络负担,还可能因发送逻辑自身变成新长任务。
- 使用
navigator.sendBeacon()发送,确保页面卸载时数据不丢失 - 每次上报至少包含:
duration、startTime、location.pathname、isMobile - 设置 15–30 秒汇总周期;缓冲区满 10 条也强制上报,防丢失
- 避免在回调里直接调用
fetch—— 它会引入新网络请求,干扰性能数据
不复杂但容易忽略。











