Runtime Diagnostics Panel
import { RenderRuntimeDiagnosticsPanel, type RuntimeDiagnosticsState } from 'ds-ui'
Runtime Diagnostics Panel 是运行时诊断面板,用于查看 paint/layout request、热点聚合、调用栈、dirty target 和诊断快照。它是排查“为什么一直重绘”“为什么一直 layout”的主要工具。
在完整应用中,推荐通过 DevTools 开发工具 的 Runtime tab 打开该能力。单独使用 RenderRuntimeDiagnosticsPanel 更适合 demo、测试或自定义诊断容器。
和 运行时诊断指南 的区别:
- 指南讲排查流程和操作顺序。
- 本页讲面板字段、指标含义、过滤方式和典型案例。
核心数据结构
RenderRuntimeDiagnosticsPanel 接收 RuntimeDiagnosticsState:
const state: RuntimeDiagnosticsState = { paintRequestDebugEnabled: true, paintRequests: [],} const panel = new RenderRuntimeDiagnosticsPanel({ state })
实际应用中,paintRequests 应由运行时 host 收集。面板只负责展示、过滤、聚合和查看详情。
构造参数
| 参数 | 类型 | 说明 |
|---|---|---|
state |
RuntimeDiagnosticsState |
当前诊断状态。 |
onRefresh |
() => RuntimeDiagnosticsState |
刷新状态。 |
onTogglePaintRequestDebug |
() => RuntimeDiagnosticsState |
开关 paint request debug。 |
onClearPaintRequestHistory |
() => RuntimeDiagnosticsState |
清空请求历史。 |
onExportDiagnosticsSnapshot |
() => RuntimeDiagnosticsSnapshot |
导出诊断快照。 |
面板区域
| 区域 | 说明 |
|---|---|
| Toolbar | 刷新、开关 stack/debug、清空历史、导出快照。 |
| Filter Bar | 切换 Requests/Hotspots、kind、source 和搜索。 |
| Summary | 当前请求数量、过滤数量、热点数量、stack 状态。 |
| List | 请求列表或热点列表。 |
| Detail Inspector | 选中 request/hotspot 的完整对象详情。 |
Requests 视图
Requests 视图保留时间顺序,适合观察“刚才那一次操作触发了什么”。
重点字段:
| 字段 | 含义 | 判断方式 |
|---|---|---|
seq |
请求序号 | 连续增长说明仍在产生请求。 |
kind |
frame 或 layout |
layout 高频通常比纯 paint 更危险。 |
source |
请求来源 | pipeline、overlay、runtime、window、debug 等。 |
target |
发起请求的 RenderObject | 首先定位到具体组件。 |
reason |
请求原因 | 判断是否是合法交互、动画、光标或异常同步。 |
alreadyScheduled |
当时是否已有帧调度 | 大量 true 说明请求过密。 |
layoutNeeded |
当时是否已有 layout 需求 | 持续 true 可能存在 layout 循环。 |
dirtyLayers |
脏图层 | 判断局部 dirty 是否被放大。 |
stack |
调用栈 | 定位触发 markNeedsLayout/markNeedsPaint 的代码。 |
Hotspots 视图
Hotspots 按 target、kind、source、reason 聚合,适合观察长时间采样中的最高频来源。
重点字段:
| 字段 | 含义 |
|---|---|
count |
同类请求次数。 |
firstSeq / lastSeq |
首次和最近请求序号。 |
firstTime / lastTime |
首次和最近请求时间。 |
alreadyScheduledCount |
请求时已经有帧调度的次数。 |
layoutNeededCount |
请求时已经有 layout 需求的次数。 |
dirtyLayerCount |
涉及 dirty layer 数量。 |
layoutTargets |
本次聚合涉及的 layout 目标。 |
paintTargets |
本次聚合涉及的 paint 目标。 |
排查时优先看 count 最高且业务上不应持续变化的 hotspot。
过滤器
| 过滤器 | 用途 |
|---|---|
| View Mode | 在 Requests 和 Hotspots 间切换。 |
| Kind Filter | 只看 frame 或 layout。 |
| Source Filter | 只看 pipeline、overlay、runtime、window、debug 等来源。 |
| Query Filter | 按 target、reason、source、stack 文本搜索。 |
常用组合:
- 空闲持续重排:
kind = layout,按 count 看 hotspots。 - hover 卡顿:query 输入组件名或
hover。 - 弹窗问题:
source = overlay。 - 窗口问题:
source = window。
debugState
面板自身提供 debugState(),适合测试和诊断:
| 字段 | 说明 |
|---|---|
requestCount |
原始请求数量。 |
filteredRequestCount |
当前过滤后的请求数量。 |
aggregateCount |
当前热点数量。 |
selectedSeq |
当前选中的 request seq。 |
selectedAggregateKey |
当前选中的 hotspot key。 |
paintRequestDebugEnabled |
是否开启请求调试。 |
viewMode |
当前视图模式。 |
kindFilter |
当前 kind 过滤。 |
sourceFilter |
当前 source 过滤。 |
queryFilter |
当前搜索文本。 |
listLabels |
当前列表显示文本。 |
detailRoots |
详情 ObjectInspector 根路径。 |
summaryText |
面板摘要文本。 |
典型案例
空闲时持续 layout
现象:
kind: layout
target: RenderReviewSidebar
stack: RenderReviewSidebar.setItems -> RenderMedicalRecordEditor.performLayout
判断:
performLayout() 中同步调用子组件 setter,且 setter 即使数据不变也会 markNeedsLayout()。
修复:
- 对传入 items 做签名比较。
- 数据没变时不调用 setter。
- 避免 layout 阶段创建新数组再写入子组件。
空闲时持续 paint
现象:
kind: frame
target: RenderTabs
stack: underline animation reset -> RenderTabs._syncUnderline
判断:
动画控制器可能在没有 tab 切换时反复 reset,导致持续 paint。
修复:
- 只在 active tab 或目标 underline 变化时启动动画。
- 相同值不 reset 动画。
- 动画结束后停止通知。
输入光标导致大文档重绘
现象:
kind: frame
target: RenderMedicalRecordEditor
reason: caret
判断:
光标闪烁不应让整个大文档持续重绘。需要检查 dirty 范围是否被放大。
修复:
- 光标绘制走局部 dirty rect。
- 光标闪烁不触发布局。
- 可视页绘制不要因为光标而扫描全量页。
overlay 请求过多
现象:
source: overlay
target: PopupHost
判断:
popup、tooltip、dropdown 或 modal 可能在滚动/hover 中反复刷新位置或重建内容。
修复:
- 只有 anchor rect 变化时刷新 popup 位置。
- hover tooltip 加延迟和相等判断。
- 弹窗内容数据没变时不重建树。
快照导出
导出快照适合现场问题复现:
- 开启 paint request debug。
- 执行最小复现动作。
- 导出 Runtime Diagnostics Snapshot。
- 提交给开发分析。
快照应脱敏:
- 不包含患者隐私。
- 不包含账号 token。
- 不包含完整病历正文。
- 不包含超大业务数组。
性能注意事项
- 开启 stack 采集会增加额外开销,只在排查时打开。
- 请求历史应有上限,不要无限保存。
- 面板本身也会布局和绘制,复杂问题复现后应关闭它再验证真实性能。
- 详情 ObjectInspector 展开大对象时应分批,避免诊断工具造成新的卡顿。
和其他工具的分工
| 工具 | 负责 |
|---|---|
| Runtime Diagnostics Panel | 谁请求 layout/paint,为什么请求。 |
| 性能浮层 | 当前帧是否慢,趋势是否异常。 |
| Layout Inspector | 节点在哪里,rect 和命中是否正确。 |
| ObjectInspector | 对象内部状态是什么。 |
| 浏览器 Performance | 浏览器主线程具体耗时在哪里。 |
| Heap Snapshot | 关闭后谁还持有对象。 |