PerformanceObserver 与长任务
本节用 PerformanceObserver 收集长任务条目,并明确“没有条目”与“观察器失效”的区别。
js
const entries = []
const supported = typeof PerformanceObserver !== 'undefined' && PerformanceObserver.supportedEntryTypes?.includes('longtask')
if (supported) {
const observer = new PerformanceObserver(list => entries.push(...list.getEntries()))
observer.observe({ type: 'longtask', buffered: true })
const end = performance.now() + 60
while (performance.now() < end) {}
setTimeout(() => { console.log(entries.map(entry => entry.duration)); observer.disconnect() }, 0)
} else {
console.log('longtask unsupported')
}支持 longtask 的浏览器应记录至少一个超过 50ms 的条目;不支持该类型时记录能力差异,不把空数组当成优化成功。
机制拆解
PerformanceObserver 异步接收指定类型的性能条目。longtask 反映主线程超过阈值的任务,不等于一次交互的总耗时;需要制造对照、记录浏览器是否支持并在完成后断开观察器。
边界与失败路径
- 所有权:监听器、observer、worker、连接、缓存和焦点都有创建者与释放时机;页面隐藏、路由离开和元素移除时都要验证。
- 宿主差异:SSR、Web Worker、Shadow DOM、跨文档、跨源和辅助技术不会共享同一套全局对象与事件路径。
- 错误分类:取消、超时、权限拒绝、协议错误、配额不足和浏览器不支持应分别进入可观察状态。
- 安全边界:用户输入、URL、HTML、消息和持久化数据不能仅因为来自同源或类型正确就视为可信。
可运行实验
先运行 60ms 同步循环制造 longtask,再移除循环;记录条目数量、duration 和浏览器支持情况,最后调用 disconnect() 验证观察器不再追加日志。
实验记录要包含运行时、输入步骤、预期输出、实际日志和未覆盖的宿主差异。
练习
- 制造超过 50ms 的循环,记录 longtask 条目 duration。
- 移除循环并断言条目为空或明显减少,最后 disconnect。
- 区分 PerformanceObserver 条目、页面总响应时间和 FPS。 查看本节答案
下一步
完成练习后回到本章概览,按下一篇继续;遇到跨章节故障,先回到本节的所有权与宿主边界。