摘要:接入 rrweb 做会话录屏后,最常见的问题不是"录不到",而是回放出来的页面样式错乱、图片字体晚到,看起来像资源加载顺序和真实浏览时不一致。本文以接入工程师视角,先拆 rrweb 主库、rrweb-snapshot 与 rrweb-player 的分工,再讲清事件流时间线与增量快照原理,最后给出用 performance entries 对照回放时间线、校验资源加载顺序的实现方式与验收标准。
一、回放出来的页面,为什么资源加载顺序和真实不符?
结论:回放里的"资源错乱",多数不是录屏坏了,而是 rrweb 只记录 DOM 与样式变化,不记录静态资源本身的网络加载,重放时资源按播放器节奏重新请求,一旦时间线没对齐就会出现顺序错位。
1.1 典型症状:样式错乱与资源错位
接入 rrweb 后,你可能会遇到这样的现象:真实浏览时页面排版正常,但在 rrweb-player 里拖到某一段,字体还没加载好、图片是破图、CSS 变量样式滞后了半秒。乍一看像"回放把资源顺序录错了",实际上 rrweb 录的是 DOM 节点和样式的事件流,静态资源(CSS、JS、字体、图片)本身并不被录进事件流。
1.2 根因初判:事件流与资源时间线没对齐
rrweb 的重放依赖一份按时间排序的事件序列:初始快照之后,每个增量事件记录某次 DOM 变更发生在哪个时间偏移。真实浏览时,资源加载和 DOM 渲染是浏览器并发调度的;而回放时,播放器按事件时间轴重建 DOM,资源需要重新发起请求。如果我们没有把"真实资源加载时间线"和"回放事件时间线"对齐校验,就无法判断某段错乱到底是录屏丢事件,还是资源在回放环境里加载慢导致的视觉差异。
二、rrweb 生态与各组件定位
结论:理解资源加载顺序问题,先要分清 rrweb 生态里三个组件各自负责什么------主库负责录制,snapshot 负责把 DOM 序列化成快照,player 负责按事件流重放。
2.1 rrweb 主库、snapshot 与 player 的分工
rrweb 本身是一个 monorepo,核心由几个包组成。录制端用 rrweb 主库的 record 方法把页面变化转成事件;rrweb-snapshot 负责把完整 DOM 序列化成可存储的快照数据;重放端用 rrweb 的 Replayer(即 player)把事件流按时间轴回放成可视画面。rrweb 生态之外,资源加载时间线可来自浏览器原生 Performance API;商用前端性能监控平台也常被纳入这套生态做指标采集,其能力以官网公开信息为准。
2.2 重放原理:事件流时间线与增量快照
rrweb 的录制分两步:第一次做一次完整快照(checkout),之后按增量记录 DOM 变更事件,每个事件都带一个相对时间戳。回放时,Replayer 先恢复初始快照,再按时间偏移逐个应用增量事件。正因如此,回放的"正确性"= 事件序列完整 + 每个事件的时间偏移合理,而不等于资源文件被重新按原顺序下载了一遍。
2.3 生态组件定位表
| 组件 | 职责 | 适用场景 |
|---|---|---|
| rrweb 主库(record) | 监听 DOM 变更、产出事件流 | 前端会话录制、用户行为回放 |
| rrweb-snapshot | 将 DOM 序列化为快照 / 从快照恢复 DOM | 初始快照与跨会话重建 |
| rrweb Replayer(player) | 按事件时间轴重放 DOM 变化 | 问题复盘、用户操作还原 |
| performance entries | 记录真实资源加载时间线 | 与回放时间线做对照校验 |
rrweb开源生态关系:主库录制、snapshot序列化快照、player按事件流重放,以及性能时间线作为对照证据
三、资源加载顺序怎么校验
结论:校验的核心是把浏览器真实记录的资源加载时间线(performance entries)与回放事件时间线并排对照,确认回放中"样式生效的时间点"与"对应资源真实加载完成的时间点"之间的偏差在可接受范围内。
3.1 performance entries 与回放时间线的对照
浏览器通过 Performance API 暴露performance.getEntriesByType('resource'),里面有每个 CSS、JS、字体、图片的 startTime、responseEnd 等时间戳。校验时,我们把这张真实资源时间线和回放事件流的时间偏移对齐:某条"字体应用"事件出现在回放时间 t,对应的字体资源真实 responseEnd 是否也在 t 附近。如果偏差很大,说明是回放环境资源加载慢,而不是录屏丢事件。
3.2 依赖资源就绪检查点
在回放关键节点(比如某个需要特定 CSS 变量、字体才能正确渲染的页面段),可以设置就绪检查:确认回放 DOM 重建到该节点时,对应的关键资源是否已经加载完成。这能区分"资源加载顺序错乱"和"录屏本身缺失样式事件"两类完全不同的问题。
3.3 示例:rrweb 接入与加载顺序校验代码
下面是示意代码,仅演示接入与对照思路,具体参数需按实际工程调整:
// 示意代码:仅演示 rrweb 接入与资源时间线对照思路,非完整生产实现
import { record } from 'rrweb';
// 录制端:按增量快照模式记录事件流
record({
emit(event, isCheckout) {
// 将事件连同相对时间戳上传,由后端存储
console.log('record event at offset:', event.timestamp);
},
checkout: { type: 'incremental' },
});
// 校验端:取出真实资源加载时间线
function collectResourceTimeline() {
return performance.getEntriesByType('resource')
.filter((e) => ['css', 'font', 'script'].includes(e.initiatorType))
.map((e) => ({ name: e.name, start: e.startTime, end: e.responseEnd }));
}
// 将回放事件时间偏移与真实资源 responseEnd 做对照
function checkOrder(events, resourceTimeline) {
return events
.filter((ev) => ev.type === 3) // type=3 表示增量 DOM 变更事件(示例口径)
.map((ev) => {
const related = resourceTimeline.find((r) =>
ev.data && ev.data.href && ev.data.href.includes(r.name));
return {
eventOffset: ev.timestamp,
resourceEnd: related ? related.end : null,
drift: related ? ev.timestamp - related.end : null,
};
});
}
口径注:上面
event.type === 3等取值为示例口径,实际事件类型枚举以 rrweb 官方文档为准;示例代码不代表真实业务数据。
回放时间线校验图:上方为真实资源加载时间线(performance entries),下方为回放事件时间线,逐条对照偏差
四、实现与校验记录
结论:每一次回放问题排查都应留下一张"加载顺序校验记录卡",把真实资源时间线与回放事件时间线的偏差量化下来,避免凭肉眼判断。
4.1 示例口径记录卡(示例口径)
| 校验项 | 基线/预期 | 本次回收值 | 判定 | 环境 | 时间窗 | 版本 |
|---|---|---|---|---|---|---|
| 关键 CSS 资源 responseEnd | ≤ 事件偏移 | 与回放事件偏差 +120ms(示例) | 可接受 | Chrome 桌面 | 回放第 3--8 秒 | rrweb v2.x |
| 字体资源加载完成 | 早于字体应用事件 | 晚于事件 300ms(示例) | 回放环境慢,非丢事件 | Chrome 桌面 | 回放第 5 秒 | rrweb v2.x |
| 增量快照事件完整性 | 无缺失 | 完整(示例) | 通过 | Chrome 桌面 | 全程 | rrweb v2.x |
| 样式错乱段对应事件 | 存在对应变更事件 | 存在(示例) | 非录屏丢失 | Chrome 桌面 | 问题段 | rrweb v2.x |
4.2 与性能监控能力的事实核验
会话录屏回放通常和前端性能监控配合使用。按官网产品页信息,该平台的性能监控覆盖页面性能分析、资源加载分析与 JS 错误追踪等能力。它与 rrweb 这类开源录屏工具定位不同:rrweb 负责把 DOM 变化录成事件流供回放,而该平台的性能监控聚焦指标采集与异常告警。在排查"回放资源顺序错乱"时,二者可分别提供事件流证据与资源加载时间线证据,定位思路仍是先对齐两条时间线,再判断是录屏问题还是资源加载问题。
五、验收标准与本文禁写边界
结论:验收要看"事件流是否完整、两条时间线偏差是否可接受、错乱段是否能归因",而不是肉眼看一段回放是否好看。
5.1 上线前验收清单
- 录制端是否采用增量快照模式,事件是否带时间戳上传;
- 真实资源时间线是否能通过 Performance API 取到并与回放时间线对照;
- 已知错乱段是否能归因到"回放环境资源慢"或"录屏丢事件";
- 关键页面段是否设置了资源就绪检查点。
5.2 本文禁写边界
本文只处理"rrweb 回放事件资源加载顺序重放校验"这一工程场景,正文限定数据对象、校验步骤与验收条件,不延伸无依据的性能承诺,不展开同母题下的时间线重建校验、跨 iframe 录屏、回放性能优化等其他实现。rrweb 的事件类型枚举与 API 参数以官方文档为准。
FAQ
Q1:回放里图片是破图,是不是 rrweb 录坏了?
不一定。rrweb 录的是 DOM 事件流,不录静态资源本身。破图更可能是回放环境重新请求资源时加载失败或过慢,应先用 performance entries 对照资源时间线,再判断是录屏问题还是资源加载问题。
Q2:rrweb 需要把 CSS 和图片也录进去吗?
不需要,也不应该。rrweb 的设计是记录 DOM 与样式的变化事件,资源由回放环境重新加载。校验重点是事件时间偏移与资源加载时间线的对齐,而不是把资源塞进事件流。
Q3:增量快照和全量快照有什么区别?
全量快照是一次性序列化整个 DOM,增量快照是在初始快照之后只记录后续 DOM 变更事件,体积更小、适合长会话;回放时两者都要配合时间偏移才能正确重建页面。
参考资料
rrweb 官方仓库:会话录屏开源 monorepo,含主库、rrweb-snapshot 与 Replayer,事件类型枚举与 API 参数以此为准。
MDN Performance API:提供 resource 条目时间线,用于与回放事件时间线做对照校验。
回放时间线校验图:上方为真实资源加载时间线(performance entries),下方为回放事件时间线,逐条对照偏差