线上白屏又复现不了的时候,我一般先看监控里有没有对应的错误和录屏,这比坐着猜快得多。
Q1: 前端监控的历史?为什么要有它?
1
蛮荒时代: window.onerror
最早的前端监控非常原始——开发者在页面中挂一个
window.onerror 全局错误监听,把错误信息通过 new Image() 发到后端。这种方式只能捕获同步的 JS 运行时错误,无法处理 Promise 异常、资源加载失败,更没有 Source Map 还原能力。2
埋点时代: 自研 SDK 与手动上报
随着业务复杂度提升,团队开始自研埋点 SDK,通过在代码中手动调用
tracker.send() 上报用户行为(PV、UV、点击事件)。这个阶段的核心痛点是埋点覆盖率低——漏埋、错埋是常态,而且 SDK 本身可能影响页面性能。3
自动化时代: Sentry 与商业 APM
Sentry 的出现改变了游戏规则。它通过全局错误捕获 + Source Map 还原 + Session Replay,让开发者能在线上精准还原用户崩溃现场。同期,Fundebug、阿里 ARMS 等商业 APM 产品也提供了开箱即用的错误监控、性能监控和行为分析能力。
4
全链路时代: 可观测性三支柱
现代前端监控已经演进为可观测性(Observability)体系,包含三大支柱:Logs(日志)、Metrics(指标)、Traces(链路追踪)。前端通过
Performance API 采集 Core Web Vitals(Core Web Vitals 指 LCP、INP、CLS;FCP、TTFB 等属于其他性能指标),结合 OpenTelemetry 标准打通前后端链路追踪。前端监控让你从”被动等用户投诉”变成”主动发现问题并精准定位”。
没有前端监控
线上出了 JS 错误,开发者完全不知道。直到用户投诉客服,客服转给产品经理,产品经理再转给开发——这时候可能已经过去好几天,影响了大量用户。
引入前端监控
JS 错误发生的瞬间,Sentry 就推送告警到钉钉群。开发者点开告警链接,Source Map 还原出错误代码行,Session Replay 回放用户操作路径,快速定位问题并修复。
Q2: MutationObserver 详解
MutationObserver 的本质是异步观察 DOM 树的变化,当 DOM 节点被增删改时触发回调。它替代了已废弃的 Mutation Events(DOMNodeInserted 等)。
MutationObserver 与 Vue 响应式系统的关系
Vue 2 的nextTick 内部优先使用 microtask(Promise.then),在不支持的降级方案中使用 MutationObserver 作为微任务的 polyfill。Vue 3 统一使用 Promise.then。
性能优化
MutationObserver 本身性能很好,但回调中的处理逻辑如果不当,可能引发性能问题:Q3: rrweb 详解
rrweb(record and replay the web)是一个开源的 Web 录制与回放库,核心能力是将用户在页面上的所有操作(DOM 变化、鼠标移动、输入、滚动)录制下来,然后在另一个环境中精确回放。1
全量快照(Snapshot)
录制开始时,rrweb 递归遍历整个 DOM 树,将每个节点序列化为 JSON 格式。这个快照包含了完整的页面状态:节点类型、属性、文本内容、CSS 样式、Canvas 内容等。
2
增量快照(Incremental Snapshot)
快照之后,rrweb 通过
MutationObserver 监听 DOM 变化,通过各类事件监听器捕获用户交互(鼠标移动、滚动、输入、Resize 等)。每个变化都被记录为一个带时间戳的事件。3
事件流序列化
所有事件按时间顺序组成一个 JSON 数组(事件流),上传到后端存储。每个事件包含:时间戳、事件类型(Mutation/MouseMove/Input/Scroll 等)、具体数据。
4
回放重建
回放端加载事件流,先用全量快照重建初始 DOM,然后按时间戳依次执行增量事件,精确还原用户的操作过程。回放端还会模拟鼠标指针移动、输入框打字动画等视觉效果。
rrweb 与 Sentry Replay 的关系
Sentry 的 Session Replay 功能底层就是基于 rrweb 实现的。Sentry 在 rrweb 的基础上做了以下增强:- 压缩与采样:对事件流进行 gzip 压缩,支持按采样率上报,降低带宽消耗。
- 隐私保护:默认对输入框内容做脱敏处理(masking),支持自定义隐私规则。
- 性能优化:对高频事件(如 mousemove)做节流,减少事件流体积。
- 关联错误上下文:将录屏数据与 Sentry 错误事件关联,点击错误即可回放崩溃前的用户操作。
使用场景
rrweb 序列化原理详解
rrweb 全量快照的核心是将 DOM 树递归序列化为一棵 JSON 树。每个节点被映射为一个SerializedNode 对象,包含 type、tagName、attributes、childNodes 等字段。
属性过滤规则: rrweb 在序列化属性时会过滤掉事件处理器(
onclick、onerror 等),因为这些是函数引用,无法序列化为 JSON。对于 src、href 等资源 URL,rrweb 会将其转为绝对路径。对于 <link rel="stylesheet">,rrweb 会直接序列化计算后的 CSS 规则(getComputedStyle),确保回放时样式一致。
增量快照的事件类型
rrweb 的增量快照覆盖了多类事件,常见的事件类型包括:rrweb 的性能优化
rrweb 在生产环境中面临的核心挑战是事件流体积和录制性能开销。以下是它采用的优化策略: 采样策略:
事件流体积控制(生产级方案):
rrweb 的隐私保护
Session Replay 涉及用户隐私数据,rrweb 提供了多层隐私保护机制:rrweb 2.0 新特性
rrweb 2.0 在 1.x 的基础上做了重大升级,解决了之前无法录制 Shadow DOM、Canvas 和 iframe 的痛点:如何自己实现一个简易版 rrweb
理解 rrweb 核心原理的最好方式是亲手实现一个最小版本。以下是 100 行代码的简化实现:rrweb 的核心是”全量快照 + 增量事件流”:Snapshot 序列化整个 DOM 树为 JSON,增量快照通过 MutationObserver + 事件监听捕获所有变化,两者结合实现精确的录屏回放。隐私保护(maskAllInputs)和性能优化(采样 + 压缩)是生产环境的两大关键。
Q4: 前端监控系统搭建思路
一个完整的前端监控系统包含两大核心模块:错误监控和行为监控,外加数据上报策略、SDK 设计和后台架构。错误监控
行为监控
数据上报策略
Core Web Vitals 上报
CWV 是字段数据(field data)——必须在真实用户浏览器里测,而不是在本地 Lighthouse 跑分。推荐用官方的web-vitals 库,它已经处理好了各指标的计算口径和浏览器差异。
CWV 大多只在页面生命周期结束前才“定型”(例如 LCP 可能随用户滚动继续更新)。因此在
visibilitychange 变为 hidden 时用 sendBeacon 发送,既拿到最终值,又不阻塞页面卸载。不要用 unload 事件,它在移动端不可靠。监控 SDK 设计
一个生产级的前端监控 SDK 需要解决 3 个核心问题:采集什么(自动 vs 手动)、怎么上报(批量 + 重试 + 离线)、怎么控制开销(采样 + 去重)。Source Map 还原
线上代码经过压缩后,错误堆栈指向的是压缩文件(app.min.js:1:23456),无法直接定位源码。Source Map 还原是将压缩代码的错误位置映射回源码位置的关键能力。
.map)包含一个 VLQ 编码的映射表,记录了压缩文件中每个字符位置对应的源文件、源行号、源列号。还原工具读取这个映射表,将压缩位置翻译为源码位置。
两种还原方式:
监控后台设计
一个完整的监控后台需要 4 个核心模块:前端监控 SDK = 采样策略(控制开销) + 批量上报(减少请求) + 失败重试(数据不丢) + 离线缓存(兜底方案),Source Map 还原是精准定位线上 Bug 的关键能力。
Q5: 高频面试题
MutationObserver 和 Vue 的 nextTick 有什么关系?
MutationObserver 和 Vue 的 nextTick 有什么关系?
答题要点:
从 Vue 2 的 nextTick 降级策略切入,说明 MutationObserver 作为微任务 polyfill 的角色。高分回答:
“Vue 2 的
nextTick 需要在当前 DOM 更新完成后执行回调,本质上是利用微任务的特性。Vue 2 内部有一个优先级链:Promise.then > MutationObserver > setImmediate > setTimeout。MutationObserver 的回调是微任务,所以在不支持 Promise 的旧浏览器中,Vue 2 用它作为微任务的 polyfill。具体做法是创建一个文本节点,通过修改文本节点的 data 属性来触发 MutationObserver 回调。Vue 3 统一使用 Promise.then,不再需要 MutationObserver 降级。但理解这个关系很重要——它说明了 MutationObserver 在浏览器任务模型中的位置:它是微任务的一种来源。”rrweb 是怎么实现录制的?
rrweb 是怎么实现录制的?
答题要点:
必须讲清楚 Snapshot + Incremental Snapshot 两阶段,以及底层依赖的浏览器 API。高分回答:
“rrweb 的录制分为两个阶段:第一阶段:全量快照(Snapshot)。 录制开始时,rrweb 递归遍历整个 DOM 树,将每个节点序列化为 JSON。序列化内容包括节点类型、属性、文本内容、计算样式、Canvas 内容等。这相当于给页面拍了一张’照片’。第二阶段:增量快照(Incremental Snapshot)。 快照之后,rrweb 通过
MutationObserver 监听所有 DOM 变化(增删节点、属性修改、文本变化),通过事件监听器捕获用户交互(鼠标移动、滚动、输入、Resize)。每个变化都记录为一个带时间戳的事件。所有事件按时间顺序组成一个 JSON 数组上传到后端。回放时先用全量快照重建初始 DOM,再按时间戳依次执行增量事件,精确还原用户操作。Sentry 的 Session Replay 就是基于 rrweb 实现的。”sendBeacon 和 fetch keepalive 的区别?
sendBeacon 和 fetch keepalive 的区别?
答题要点:
从浏览器保证机制、兼容性、请求大小限制三个维度对比。高分回答:
“
sendBeacon 和 fetch keepalive 都能在页面关闭后完成请求发送,但有重要区别:-
浏览器保证级别不同。
sendBeacon是浏览器专门为’页面卸载时数据上报’设计的 API,浏览器会优先保证它发送成功。fetch keepalive是fetch的一个选项,保证级别不如 sendBeacon。 -
请求大小限制。
sendBeacon限制请求体大小为 64KB。fetch keepalive限制为 64KB(Chrome)。 -
请求方法。
sendBeacon只支持 POST。fetch keepalive支持所有方法。
sendBeacon,降级用 fetch keepalive,再降级用 Image(1x1)。Source Map 还原的原理是什么?
Source Map 还原的原理是什么?
答题要点:
说明 VLQ 编码映射表的工作原理,以及服务端还原 vs 前端还原的区别。高分回答:
“线上代码经过压缩后,错误堆栈指向的是压缩文件(
app.min.js:1:23456),无法直接定位源码。Source Map 文件(.map)包含一个 VLQ 编码的映射表,记录了压缩文件中每个字符位置对应的源文件、源行号、源列号。还原工具读取这个映射表,将压缩位置翻译为源码位置。比如 app.min.js:1:23456 还原为 src/components/UserCard.tsx:42:15。两种还原方式:- 服务端还原(推荐): 后端收到错误堆栈后,读取 Source Map 文件做映射。Source Map 不暴露给前端,安全性高。Sentry 就是这个方案——构建时上传
.map文件到 Sentry 服务端,收到错误时自动还原。 - 前端还原: 浏览器通过
//# sourceMappingURL加载 .map 文件。仅用于开发调试,生产环境不要暴露.map文件,否则源码泄露。”
前端监控的采样策略怎么做?
前端监控的采样策略怎么做?
答题要点:
说明采样的必要性(控制开销和成本),以及不同场景的采样率设计。高分回答:
“全量上报会导致:1)网络带宽浪费,2)后端存储成本暴增,3)SDK 本身影响页面性能。所以必须做采样。采样率设计原则:
- 错误监控: 一律全量上报,不采样。线上 Bug 不能遗漏。
- 性能监控: 采样率可高一些。性能数据是统计指标,需要足够样本量才能算分位数,具体比例按日活和后端成本定。
- 行为监控: 采样率可以更低。点击、曝光等行为数据量巨大,低采样率即能反映趋势。
Math.random() < sampleRate 判断是否上报。也可以在初始化时一次性决定是否注册某类采集,避免每条事件都做一次随机判断(少一点运行时开销)。监控 SDK 的 beforeSend 钩子有什么用?
监控 SDK 的 beforeSend 钩子有什么用?
答题要点:
说明 beforeSend 在数据脱敏、过滤噪音、补充上下文三个场景的作用。高分回答:
“
beforeSend 是监控 SDK 在数据上报前的最后一个拦截点,有三个核心用途:1. 过滤噪音: 过滤掉无价值的错误。比如跨域脚本的 Script error. 没有堆栈信息,对排查问题毫无帮助,可以直接返回 null 过滤掉。2. 数据脱敏: 在上报前对敏感信息做脱敏。比如 URL 中的用户 ID、token 等参数,可以替换为 *** 后再上报。3. 补充上下文: 给错误数据附加业务上下文。比如当前登录用户 ID、页面版本号、灰度分组等,方便后续在监控后台按维度筛选和聚合。Sentry 的 Session Replay 和 rrweb 是什么关系?
Sentry 的 Session Replay 和 rrweb 是什么关系?
答题要点:
说明 Sentry 基于 rrweb 的增强,以及生产环境中的关键优化。高分回答:
“Sentry 的 Session Replay 底层就是基于 rrweb 实现的,但在此基础上做了大量生产级增强:1. 压缩与采样: 对事件流进行 gzip 压缩,支持按采样率只录制部分用户的 Session,降低带宽消耗。2. 隐私保护: 默认开启
maskAllInputs: true,对输入框内容做脱敏处理。支持自定义隐私规则。3. 性能优化: 对高频事件(如 mousemove)做节流,减少事件流体积。录屏体积与页面 DOM 复杂度、交互频率、录制时长都相关,实际以压缩后的事件流大小为准。4. 关联错误上下文: 这是 Sentry 最大的优势——将录屏数据与错误事件关联。用户报 Bug 后,开发者在 Sentry 后台点击错误,直接回放崩溃前的用户操作路径,精准还原 Bug 现场。简单来说:rrweb 提供了录制回放的基础能力,Sentry 在此基础上解决了隐私、性能、存储和错误关联等生产环境问题。“延伸阅读与引用参考
- rrweb 官方文档:rrweb 的核心原理(Snapshot + Incremental Snapshot)与使用指南。[1]
- Sentry Session Replay:Sentry 如何基于 rrweb 实现 Session Replay,以及隐私保护策略。[2]
- rrweb 序列化原理 - rrweb-snapshot 源码:rrweb 的 DOM 序列化核心源码,理解节点类型映射和属性过滤。[3]
- Source Map 规范 v3:Source Map 文件格式规范,理解 VLQ 编码和映射表结构。[4]
- MDN - MutationObserver:MDN 对 MutationObserver 的权威 API 文档与使用指南。[5]
- Sentry 官方文档:Sentry 错误监控平台的完整文档,包含 Source Map 上传、告警配置等。[6]
- web.dev - Session Replay 隐私最佳实践:Google 对 Session Replay 类工具的隐私保护建议。[7]
- MDN - sendBeacon:sendBeacon API 的官方文档,理解页面关闭时数据上报的最佳方案。[8]
