原生 getter 仅安全返回已聚合的性能快照,不采集不监听;长效监控需靠 performanceobserver、生命周期钩子和有限轮询持续更新内部缓存,getter 作为稳定出口供响应式系统直接依赖。

原生 Getter 本身不采集、不监听、不异步,它只负责安全、无副作用地暴露当前已聚合的性能快照。要实现“长效迭代流”监控,关键在于让 Getter 成为指标流的稳定出口,而非数据源头——背后必须由轮询、PerformanceObserver 和生命周期钩子持续注入新值。
用 Getter 封装可迭代更新的指标快照
Getter 不该执行逻辑,但非常适合返回带上下文的聚合结果。例如定义一个 PerfStream 对象:
- get lcpTime() → 返回最新一次 LCP 的 startTime(来自 PerformanceObserver 持续写入的缓存)
- get routeDurations() → 返回一个只读数组,记录每次路由跳转的 performance.measure 结果
- get memoryTrend() → 计算最近 10 次 performance.memory.usedJSHeapSize 的差值趋势,自动剔除异常抖动
所有真实采集动作(如轮询内存、监听 paint)完全独立运行,仅更新内部缓存,Getter 只做取值,零开销、线程安全、可被 Vue/React 响应式系统直接依赖。
靠 PerformanceObserver 驱动指标流更新
单页应用中,“迭代”本质是用户行为与渲染帧的持续发生。Observer 是唯一能被动响应这些事件的原生机制:
- 监听 'largest-contentful-paint':每次触发都更新
PerfStream._lcpEntry,确保lcpElementgetter 总返回最新有效节点 - 监听 'longtask':捕获主线程阻塞起止时间,按 500ms 窗口聚合进
PerfStream.longTaskBuckets,供get avgBlockingMs()计算滑动均值 - 监听 'navigation':识别 SPA 路由 pushState/popstate,自动打点并测量,填充
routeDurations数组
绑定异步生命周期,让指标具备迭代语义
脱离行为上下文的数字无法构成“流”。Getter 必须与 SPA 的真实迭代节奏对齐:
- 在
beforeEach(Vue Router)或useEffect(React Router v6)中调用performance.mark('nav-start'),跳转完成时measure并推入数组 - 封装
fetchWithPerf函数,在请求发起和响应后分别打点,将耗时归入PerfStream.apiLatency,getter 可返回 P95 或最近 5 次均值 - 滚动开始时启动空闲检测,停止 300ms 后检查
getEntriesByType('paint'),计算该次滚动区间的帧率趋势,存为scrollFpsHistory
有限频次轮询补足 Observer 盲区
有些指标没有对应事件,需轻量轮询维持流连续性:
-
performance.memory(Chrome)每 3 秒采样一次,用于观察 JS 堆缓慢泄漏,数据写入PerfStream.memorySamples -
performance.getEntriesByType('paint')每秒检查最新帧,若 2 秒无新帧则标记为“静默期”,影响get isActive()判断 - 所有轮询使用
setTimeout+performance.now()校准,避免 setInterval 时间漂移
不复杂但容易忽略:Getter 的价值不在它做了什么,而在于它把分散的采集动作收束成统一、稳定、可组合的指标流接口。











