Performance API
概念和用法
衡量和分析各种性能指标对于确保 Lynx 应用的速度和用户体验非常重要。与 Web 标准 类似,Lynx 提供了 Performance API 用于衡量 Lynx 应用性能的标准化接口,帮助开发者全面监控从初始化到渲染完成的完整性能数据。

性能事件类型
Performance API 的核心是 PerformanceEntry 对象,它是描述性能事件的基础数据结构。每个 PerformanceEntry 都具有以下基本属性:
entryType:表示性能事件的类型(如init、metric、pipeline、resource)name:表示性能事件的具体名称- 其他特定于类型的属性和时间戳信息
根据 entryType 属性,Performance API 支持以下四种主要类型的性能事件:
-
初始化事件 (
init)InitContainerEntry:容器初始化性能事件InitLynxviewEntry:LynxView 初始化性能事件InitBackgroundRuntimeEntry:后台运行时初始化性能事件
-
性能指标事件 (
metric)MetricFcpEntry:FCP(First Contentful Paint)性能指标MetricActualFmpEntry:ActualFMP(Actual First Meaningful Paint)性能指标
-
渲染流水线事件 (
pipeline)PipelineEntry:被标记的渲染流水线性能事件LoadBundleEntry:TemplateBundle 加载和首屏渲染性能事件ReloadBundleEntryTemplateBundle 重新加载性能事件
-
资源加载事件 (
resource)LazyBundleEntry:懒加载 TemplateBundle 性能事件
获取性能数据
前端开发者
为了获取上述性能事件,Performance API 提供了 PerformanceObserver 来让开发者观察性能事件,并在 Lynx Engine 产生性能事件 (PerformanceEntry) 时收到通知。
PerformanceObserver 对象提供了用于开启监听的 observe 方法和结束监听的 disconnect 方法,通过它们你可以使用 entryType 监听某个类型的 PerformanceEntry 或者 entryType.name 监听某个种类的 PerformanceEntry。
为了避免性能事件发送时,回调未注册导致的事件遗漏,应尽可能早的注册监听。
-
组件依赖
@lynx-js/react>= 0.107.0
-
监听时机
- Class 组件:在 constructor 中注册
- 函数式组件:在 useMemo 中注册
该示例展示了如何创建一个 PerformanceObserver 并监听 metric.fcp 和 pipeline 事件。
客户端开发者
客户端层面,Performance API 发送的性能事件将通过 LynxViewClient 下的 onPerformanceEvent(PerformanceEntry entry) 接口在异步线程回调。因此不建议在该回调内执行与 UI 有关的业务逻辑。
采集特定渲染流水线
渲染流水线是从触发渲染到屏幕显示的完整流程。如果你关注某些关键组件的渲染性能,可以通过设置该组件的 __lynx_timing_flag 属性来标记其所在的渲染流水线,从而监测性能表现。
当标记的渲染流水线执行完成并刷新屏幕显示后,会生成一个 PipelineEntry 性能事件。你可以通过 PerformanceObserver 获取该事件。
构建自定义的性能评估指标
不同的业务目标意味着你需要关注不同的性能指标。对 Performance API 的使用可以不局限于通过 Lynx 内置指标来分析页面性能,你也可以灵活组合不同 PerformanceEntry 提供给你的关键节点的时间,构建出一套适配你的应用程序的性能检测指标。
假如你希望关注从首屏渲染结束到首次重要数据更新的延迟,你 可以像下面的代码这样灵活组合 LoadBundleEntry 和 PipelineEntry 计算出一个属于你的性能指标 waitingDuration,它可以帮助你监测网络请求、文件读取等行为的速度,精准定位页面性能变坏的原因。

最佳实践
1. 及时注册监听器
为了避免性能事件发送时,回调未注册导致的事件遗漏,应尽可能早的注册监听:
- 在 Class 组件的 Constructor 或函数式组件的
useMemo中注册
2. 合理选择监听范围
根据业务需求选择合适的监听范围:
3. 及时清理资源
在组件卸载或不需要监听时,记得调用 disconnect() 方法清理资源:
FAQ
Q1: 我的页面是首帧直出 (Instant First-Frame Rendering,IFR)的情况下,还需要标记 Timing Flag 吗?
首帧直出 (Instant First-Frame Rendering,IFR)的页面一般不需要再手动标记 Timing Flag,但是如果标记了你依旧会收到一个 identifier 值为你标记的 TimingFlag 的 LoadBundleEntry。
Q2: 我的页面是首帧直出 (Instant First-Frame Rendering,IFR)的,那我需要如何拿到 ActualFMP 性能指标呢?
首帧直出 (Instant First-Frame Rendering,IFR)的场景一般不需要关注 ActualFMP 性能指标,只需要关注 FCP 指标即可。FCP 指标可以直接通过 MetricFcpEntry 拿到。
Q3: 可以获取懒加载组件渲染耗时吗?
可以的,在懒加载组件上标记 Timing Flag 的方式和主页面一致,可以直接在懒加载组件内使用 Timing Flag:
该方式可以获取懒加载组件渲染阶段的时间戳,关于懒 加载组件资源加载阶段的耗时参考 LazyBundleEntry 。
Q4: Performance API 回调与 Lynx 提供的其他生命周期有关系吗?
Performance API 会在获取到所有渲染流程的时间戳后触发回调,因此会在渲染上屏之后触发,和 Lynx 提供的其他生命周期没有任何执行先后的关系。
Q5: setState 回调与 Performance API 回调中,哪个会被更快触发?
见 Q4,没有任何执行先后的关系。
Q6: Timing Flag 可以重复吗?
Timing Flag 不可以重复。
如果用户注入了相同的 Timing Flag,Performance API 会在感知到第一个 Timing Flag 时就会触发回调,第二次不会再次触发。
Q7: 客户端调用 ReloadTemplate、多次调用 LoadTemplate 或前端调用 Reload 时,Performance API 是什么表现?
Lynx 3.4 版本之前:Performance API 状态会重置,会以这次加载模版的时间戳重新触发一次 LoadBundleEntry 阶段性能回调。如果前端调用 reload 但是页面内没有 UI 需要重新绘制,则不会收到回调。
Lynx 3.4 版本之后:多次调用 LoadTemplate 会多次收到 LoadBundleEntry;客户端调用 ReloadTemplate 和前端调用 Reload 会收到 ReloadBundleEntry。
Q8: 为什么我收不到 LoadBundleEntry 回调?
收不到 LoadBundleEntry 可能有以下原因:
-
首屏渲染为空,比如 LynxView 页面宽高为 0、LynxView 不在屏幕内、LynxView 没有被添加到窗口内等原因都会导致渲染为空。
-
业务注册事件监听函数过晚,可以尝试在更早的时机注册回调:
- 应当在 Class 组件的 Constructor、函数式组件的
useMemo中注册
- 应当在 Class 组件的 Constructor、函数式组件的
Q9: 我使用了 Timing Flag,为什么我收不到 PipelineEntry 回调?
使用 Timing Flag 后业务收不到 PipelineEntry 回调可能有以下原因:
-
业务注册事件监听函数过晚,参考 Q8 的解决方案
-
Timing Flag 写在 Component 上,同时开启了 removeComponentElement 开关,会导致 Timing 无法感知到该 Timing Flag,进而无法生效
-
Timing Flag 写在一些没有 UI 节点的标签上是无效的,如
<inline text/>,<block/>,<template/>等 -
同一个 timing flag 不会多次回调,见 Q6
Q10: 我要如何验证 Timing Flag 接入成功了呢?
可以通过本地 Trace 验证,也可以注册监听回调,验证是否触发回调事件。
Q11: 我的页面 ActualFMP 指标特别大,可能是什么原因呢?
检查是否有预加载,在预加载场景下 ActualFMP 指标的起点可能会特别早。
Q12: 报错 OnPipelineStart arg count must == 1
检查并保证 @lynx-js/react 版本不小于 0.107.1 。

