new.target 不能直接测量耗时,但可作为精准识别实例化类的元信息锚点,在构造函数入口统一埋点、结合 performance.now() 计时并写入只读字段,再通过采集-聚合-告警三层流水线实现轻量审计。

new.target 本身不能直接测量耗时,也不能自动上报或聚合数据。但它能精准识别“谁被实例化了”,是构建自动化审计链路中不可替代的元信息锚点。真正可行的做法,是把 new.target 作为触发器,在构造函数入口统一埋点,再结合轻量计时与只读字段固化结果。
利用 new.target 定位真实构造类并启动计时
new.target 在构造函数第一行就可用,且始终指向最末端被 new 的类(如 PhonePC 而非基类 ReaderCoreIdentity),这避免了 this.constructor.name 在动态继承或代理场景下的失真问题。
- 在基类构造函数开头立即记录起始时间:
const start = performance.now() - 使用
new.target.name获取组件类型,用于后续分类统计 - 确保所有核心组件都继承同一基类(如
AuditConstructBase),否则无法统一拦截
在构造完成时写入只读耗时字段
只读属性不参与执行,但可安全承载审计所需的最终结果。关键不是“让它计时”,而是“让它存可信结果”:
- 构造逻辑结束、关键状态就绪后(如
dataId已生成),计算duration = performance.now() - start - 将其挂载为 getter-only 属性,例如:
Object.defineProperty(this, '_initDurationMs', { value: duration, writable: false, enumerable: true, configurable: false }); - 不建议用
class字段或Symbol存储——审计服务需批量读取,简单可枚举的自有属性更稳定
搭建三层轻量审计流水线
仅靠前端埋点不够,必须配套采集、聚合、告警能力:
-
采集层:通过构建时插件(如 Babel 插件)或运行时遍历(如
WeakMap缓存所有继承自AuditConstructBase的实例),自动提取_initDurationMs和new.target.name - 聚合层:按组件名、页面阶段(首屏/懒加载)、设备形态分组,统计 P50/P90、异常占比(如 >300ms)
- 告警层:当某组件连续 3 次 P90 超阈值,或单次突破 1s,自动在 PR 中插入评论,附带调用栈快照与资源水位截图
避开几个典型误区
- 不要在构造函数里做 DOM 操作、
fetch或setTimeout——这些会污染耗时数据,应移至onReady或init() -
performance.now()在 WebView2 多进程环境下可能跨进程不一致,确保计时与写入在同一个 JS 执行上下文中完成 - 若组件支持 SSR 或预渲染,服务端下发的
dataId等字段不应影响客户端耗时计算逻辑——构造耗时只反映客户端 JS 初始化开销
不复杂但容易忽略。











