想象你是这座城市最大商场的安保中心负责人。你的工作不是亲自巡逻,而是盯着满墙的监控屏幕——哪层楼的消防报警器闪了红灯,哪条通道拥挤到快要堵死,哪位顾客在每个橱窗前停留了多久,哪位保安该被调度去支援。商场不能等顾客摔倒、电梯停运才发现问题,前端应用也不能等用户点了没反应、白屏了才去排查。这套“全域感知 + 实时告警 + 行为追踪”的安保体系,就是前端世界里的监控与埋点。 前端监控用代码筑起一张无形的摄像头网络:JS 错误监控捕捉线上异常,sourceMap 还原事故现场,性能监控盯紧加载与交互体验,用户行为埋点记录点击与浏览轨迹,再通过数据上报策略汇聚到服务平台,最后由异常聚合与告警把噪音提炼成行动项。对 AI 从业者而言,这些在线数据就是模型和功能迭代的“地基燃料”。

岗位关联

学会前端监控与埋点,等于掌握线上应用的“体检雷达”与“事故黑匣子”——这是保障用户体验、驱动数据决策的核心技能,也是前端工程化能力的分水岭。

目录
  1. 可视化演示
  2. JS错误监控 — 网站的“烟感报警器”
  3. 性能监控指标 — 网页通道的拥堵地图
  4. 用户行为埋点 — 商场里的顾客动线追踪
  5. 数据上报策略 — 安保巡逻的汇报纪律
  6. 异常聚合告警 — 中控室的合并归类研判
  7. Sentry方案 — 采购成熟的安保系统
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示前端监控三大核心:JS错误捕获与sourceMap还原、Web Vitals性能指标实时监控、以及事件埋点→采样→批量→上报→聚合的数据管道。交互切换不同监控维度。

本节配有交互动效(进入视口后自动加载,约 3KB)。

JS错误监控与sourceMap还原 运行时错误→捕获→采样→上报到Sentry sourceMap还原压缩代码原始位置 error.stack → sourceMap → origin SDK全局捕获异常并通过sourceMap定位源码

JS错误监控 — 网站的“烟感报警器”

商场每一层都配有烟雾报警器与水浸传感器,一旦厨房线路短路或水管爆裂,传感信号会立刻汇入中控室大屏。JS 错误监控就是为网页安装的“报警器网络”:不是等顾客被烟呛到才开始排查,而是在异常发生的瞬间,警报已经亮起。

浏览器为前端工程师提供了几个现成的“报警器”。window.onerror 和 window.addEventListener('error') 可以捕获全局的 JS 运行时错误——那些没有被任何 try/catch 处理的“漏网之鱼”;window.addEventListener('unhandledrejection') 专门捕捉 Promise 链中被 reject 却无人处理的“孤儿异常”;而 img、script、link 等资源加载失败属于另一类不冒泡的错误,需要在捕获阶段监听 error 事件才能察觉。

更棘手的是,线上代码经过压缩混淆,报错堆栈形如 at e (a.js:1:3650),完全看不出原始逻辑。这时需要借助构建工具生成的 sourceMap 文件,将压缩后的行列号映射回源码。sourceMap 的核心是 mappings 字段,用 base64 VLQ 编码保存了压缩代码与原始代码的位置映射关系,让“回溯事故现场”成为可能。

就像中控室盯着“每千次客流触发几次火警”的比率而非绝对次数——大促时客流翻倍,火警绝对次数增加是正常的,比率陡增才是真正的险情。错误率正是归一化后的“异常血压”,排除了流量干扰,直指应用本身的质量波动。

错误率=JS错误次数页面访问总数×100%\displaystyle \text{错误率} = \frac{\text{JS错误次数}}{\text{页面访问总数}} \times 100\%
  1. JS 错误次数统计周期内 window.onerror 与 error 捕获到的所有 JS 运行时错误的总数,它是分子。
    JS错误次数=∑各类JS运行时错误事件\text{JS错误次数} = \sum \text{各类JS运行时错误事件}
  2. 页面访问总数同一周期内页面成功加载(PV)的次数,表示错误发生的基本盘有多大。
    页面访问总数=PV 总数\text{页面访问总数} = \text{PV 总数}
  3. 乘以 100%将比率换算成百分数,便于与人工设定的告警阈值直接比较。
    ×100%\times 100\%

性能监控指标 — 网页通道的拥堵地图

中控室里除了看火警,还要盯各层通道的人流热力图:哪个扶梯口堵成一团,哪条通道常年空置。顾客逛得舒不舒服,决定商场业绩;页面加载快不快、交互顺不顺,决定产品留存。性能监控便是给网页通道画“拥堵地图”。

Google 在 2020 年代提出了 Web Vitals 核心指标体系,用三个数字给真实用户体验打分:LCP(Largest Contentful Paint)衡量首屏最大内容的渲染时间,建议低于 2.5 秒;FID(First Input Delay)衡量用户第一次点击页面到能响应的时间,建议低于 100 毫秒;CLS(Cumulative Layout Shift)衡量页面元素的移动幅度,建议低于 0.1。

除了三大核心,还有 FP(First Paint)首次像素绘制、FCP(First Contentful Paint)首个内容绘制、TTI(Time to Interactive)可交互时间等辅助指标。这些数字从哪里来?答案是 Performance API。浏览器通过 PerformanceObserver 可以订阅各种性能条目——导航计时、资源加载、长任务等。工程师还可以用 performance.mark 与 performance.measure 自定义打点,测量某个业务功能的耗时。

这就像给通道的“拥堵度”打分:不仅要看有多少人堵在入口(影响比例),还要看队伍排得离入口多远(距离比例)。CLS 越低,网页就像商场里畅通无阻的动线,用户不会因为按钮突然弹走而点错。

CLS=∑i=1n(影响比例i×距离比例i)\displaystyle \text{CLS} = \sum_{i=1}^{n} (\text{影响比例}_i \times \text{距离比例}_i)
  1. 影响比例元素在视口中的可见面积占视口面积的比例,元素越大,这一项越大。
    影响比例i=元素面积视口面积\text{影响比例}_i = \frac{\text{元素面积}}{\text{视口面积}}
  2. 距离比例元素相对视口的移动距离与视口高度之比,元素“跳得越远”,这一项越大。
    距离比例i=移动距离视口高度\text{距离比例}_i = \frac{\text{移动距离}}{\text{视口高度}}
  3. 逐次累加把每次布局偏移的“影响 × 距离”求和,得到累计值。CLS 衡量的是页面在整个生命周期里“晃动”了多少。
    CLS=∑i=1n\text{CLS} = \sum_{i=1}^{n}

用户行为埋点 — 商场里的顾客动线追踪

商场最值钱的数据,不是顾客最终买走了什么,而是他们在每个橱窗前停留了多久、先逛了哪一层、在哪个岔路口折返。前端埋点做的就是这份“逛街动线”的记录工作。

埋点体系按层次分三类:第一层是 PV/UV 统计——PV(Page View)记录页面被浏览的次数,UV(Unique Visitor)通过设备指纹或用户 ID 记录独立访客数;第二层是事件埋点——点击、输入、滑动,以及加购、支付这类自定义业务事件;第三层是曝光埋点——某个推荐位进入视口时上报,通常用 IntersectionObserver 监听可见性。

埋点落地的姿势很关键。业界流行的做法是开发一个独立的埋点 SDK,业务代码只调用统一的 track(eventName, payload) 接口,SDK 内部负责上下文采集(页面路径、设备、UA、时间)、队列缓冲、批量上报。这样埋点逻辑与业务逻辑解耦,后续调整采样策略或上报通道,业务代码一行都不用改。SDK 还要处理“上传失败”“上报去重”“敏感字段过滤”等细节。

就像商场的动线报告如果掺了大量重复刷卡记录,数据分析师就得花大量时间清洗。埋点有效率就是在源头保证“记录一条,顶用一条”,让后续的用户增长分析建立在干净的地基上。

埋点有效率=有效事件数上报事件总数×100%\displaystyle \text{埋点有效率} = \frac{\text{有效事件数}}{\text{上报事件总数}} \times 100\%
  1. 有效事件数满足数据规范、能被分析系统识别并使用的事件条数。
    有效事件数=通过数据校验的事件条数\text{有效事件数} = \text{通过数据校验的事件条数}
  2. 上报事件总数SDK 实际发送到服务端的事件条数,包括缺失参数、类型异常的数据。
    上报事件总数=SDK 发出的全部事件\text{上报事件总数} = \text{SDK 发出的全部事件}
  3. 乘以 100%用百分数衡量埋点管道的“信号纯度”,有效率过低通常意味着上报了太多垃圾数据或字段名不统一。
    ×100%\times 100\%

数据上报策略 — 安保巡逻的汇报纪律

安保巡逻不会每看到一地垃圾就跑回中控室汇报一次,而是按路线巡逻、定时汇总、遇重大情况才紧急呼叫。数据上报的逻辑同理:要在“及时性”与“对业务性能的影响”之间找平衡。

上报方式上,传统方案是用 Image src 发一个 1×1 像素的 GET 请求,简单可靠但只能携带 2KB 数据;navigator.sendBeacon 是专门为“离开页面时上报”设计的 API,在 unload 场景下也能可靠送达,如今已广泛使用;fetch 上报则适合需要携带复杂请求头和大体量的场景。选择依据是:上报的数据是否紧迫、数据量多大、用户是否还在页面上。

上报策略有三件事:采样(Sample)、批量(Batch)、重试(Retry)。采样用随机数或哈希实现——哈希采样更友好,它能保证同一用户落在同一种哈希分组里,行为数据可关联。批量发送是攒够数量(如 10 条)或超时(如 5 秒)再带上一个 batchId 发出,减少请求次数。失败重试要使用指数退避:第 1 次失败等 1 秒重试,第 2 次等 2 秒,第 3 次等 4 秒……避免故障时全网重试造成雪崩。

这个公式解答了“采样率设多少才够”的困惑。保安抽查顾客满意度时,拦下 100 个人就能把误差压到可接受范围,不需要拦住每一位顾客。数据采样同理:几千条样本已经足够支撑可靠的分析结论,剩下的开销可以省下来换取业务的流畅。

σ=p(1−p)n\displaystyle \sigma = \sqrt{\frac{p(1-p)}{n}}
  1. p某个事件在总体中的真实发生率(比如 2% 的页面会触发某错误)。
    p=真实发生率p = \text{真实发生率}
  2. n采样后实际收到的样本量,样本越多,估计越准。
    n=采样样本数n = \text{采样样本数}
  3. σ采样导致的估计误差标准差,它告诉我们采样得到的错误率与真实值有多接近。
    σ=p(1−p)n\sigma = \sqrt{\frac{p(1-p)}{n}}

异常聚合告警 — 中控室的合并归类研判

中控室如果每响一声火警就给消防队打一次电话,消防队很快会因“狼来了”而精神麻木。合格的中控员会把同一区域反复出现的报警合并成一张工单,研判等级后再决定是否出动。异常聚合与告警正是这个“合并归类、分级上报”的工序。

海量错误日志的原始形态是“一堆文本”,首先要去重。去重的关键是计算错误指纹(fingerprint)——将错误的堆栈帧、错误类型、关键参数做哈希,得到一个短字符串,指纹相同的错误视为同一个 bug。接着做堆栈聚合:同一个 bug 在真实用户那里堆栈会略有差异(比如函数参数不同),需要用相似度算法将相近堆栈归入同一个 issue。

告警策略设计要平衡灵敏度与噪音。常见做法是“阈值 + 持续时间”双条件:例如错误率超过 1% 并持续 5 分钟才触发告警,可过滤瞬时抖动。更成熟的团队会引入 SLO(Service Level Objective)——以“过去 7 天错误率低于 1%”作为目标,SLO 逼近红线时再告警。通知渠道方面,配合值班轮转,用邮件、钉钉/企微机器人、电话保证“告警有人理”。

这正是保安队长的工作台:几十条散乱的“报警记录”,经过指纹比对和堆栈聚类,浓缩成几行“待处理工单”。聚合后的告警才有力量——它把千万级噪音变成可排期的行动项,让工程师在一天最清醒的时刻处理最重要的故障。

相似度=相同堆栈帧数堆栈帧总数\displaystyle \text{相似度} = \frac{\text{相同堆栈帧数}}{\text{堆栈帧总数}}
  1. 相同堆栈帧数两条错误堆栈中函数路径重叠的层数,重叠越多说明越可能是同一个 bug。
    相同堆栈帧数=∣堆栈A∩堆栈B∣\text{相同堆栈帧数} = |\text{堆栈A} \cap \text{堆栈B}|
  2. 堆栈帧总数通常取两条堆栈中较长的那条作为分母,防止长度不同的堆栈被误判。
    堆栈帧总数=max⁡(∣堆栈A∣,∣堆栈B∣)\text{堆栈帧总数} = \max(|\text{堆栈A}|, |\text{堆栈B}|)
  3. 相似度值域为 0 到 1,超过阈值(如 0.8)就判定为同一 issue 合并处理。
    相似度∈[0,1]\text{相似度} \in [0, 1]

Sentry方案 — 采购成熟的安保系统

自建监控系统,就像商场决定自己研发摄像头、冷气管道和消防喷淋,能定制但成本极高;而 Sentry 是安保系统一体化供应商,开箱即用还持续升级。对于大多数团队,成熟开源方案是性价比最高的选择。

Sentry 是目前最流行的开源错误监控平台,前端接入只需一行安装:npm install @sentry/browser。初始化时传入的 DSN(Data Source Name)是项目在 Sentry 服务端的“识别门牌号”,告诉 SDK 把数据送往哪个项目。SDK 会自动捕获全局错误、Promise 异常、资源错误,并附带用户上下文、浏览器信息、网络请求等现场数据。

Sentry 的价值不止于采集,关键在于治理链路:上传 sourceMap 后,堆栈自动还原为源码位置,甚至关联到文件与代码行;release 字段记录发版版本,发布后新版本错误率对比一目了然;issue 自动去重聚合,团队成员可对 issue 添加标签、指派、标记已解决。数据敏感的企业还可以通过 onpremise 仓库私有化部署,把数据留在自己的服务器里。

就像商场采购安保系统后,要定期验证“是否所有摄像头都在工作”——捕获率就是 Sentry 这套系统的摄像头完好率。接入不是终点,持续观察捕获率、优化采样与上报链路,才真正让这套成熟方案变成场内可靠的“眼睛”。

错误捕获率=SDK 捕获并上报的错误数应用实际发生的错误总数×100%\displaystyle \text{错误捕获率} = \frac{\text{SDK 捕获并上报的错误数}}{\text{应用实际发生的错误总数}} \times 100\%
  1. SDK 捕获并上报的错误数Sentry 客户端实际收到并成功上报的错误数,这是分子。
    捕获数=SDK 上报到服务端的错误条数\text{捕获数} = \text{SDK 上报到服务端的错误条数}
  2. 应用实际发生的错误总数真实发生的全部错误,包含被 try/catch 吞掉、被采样过滤、上报失败的错误,这是衡量监控“覆盖率”的基线。
    实际总数=真实错误总数\text{实际总数} = \text{真实错误总数}
  3. 乘以 100%捕获率越低,说明监控盲区越大。Sentry 的 Breadcrumb、默认采样策略与 sourceMap 还原都会影响这一数字。
    ×100%\times 100\%

AI 应用场景

场景一:电商大促期间的实时性能监控

阶段:性能数据采集与异常检测

解决的问题:双 11 大促流量激增 10 倍时,传统排查完全依赖用户投诉,问题发现往往滞后数小时,客服压力巨大。AI 监控平台通过实时采集 Web Vitals 指标,用异常检测算法自动识别 LCP 突刺,将“用户感知问题”提前到“指标异常瞬间”。

具体案例:某电商平台前端监控系统接入了 AI 异常检测模型,实时分析各页面 LCP 与错误率的时间序列。大促峰值期间系统提前 20 分钟发现“商品详情页 LCP 从 2.1s 飙升到 6.8s”,自动触发告警并附上 sourceMap 还原后的代码位置,前端团队在用户大面积流失前完成了缓存策略热修。

场景二:错误智能归因与去噪

阶段:错误日志聚合与智能分类

解决的问题:线上每天产生百万级错误日志,人工按堆栈和消息分类费时费力,且容易漏掉关键信号。AI 聚类模型可以把结构相似的堆栈自动归入同一 issue,并对高频错误做根因排序。

具体案例:某中台团队在 Sentry 之上引入了基于堆栈相似度的 AI 聚类,将 100 万条错误自动归并为 237 个 issue,再依据用户影响面(UV 数、错误率)排序。最终定位到“新版上线后,旧版本浏览器不兼容 ?. 语法”这一根因,一个被淹没在噪音里的致命问题就此浮出水面。

场景三:用户行为埋点驱动增长决策

阶段:行为埋点数据采集与漏斗分析

解决的问题:产品改版后转化率下降,运营只能靠猜“用户在哪一步流失”。通过前端埋点采集的点击、曝光、停留时长数据,AI 漏斗分析可以精确定位流失环节,并给出优化建议。

具体案例:某 SaaS 产品在结算页改版后支付转化率下降 15%。埋点数据显示用户到达“确认订单”步骤的比例正常,但“点击支付按钮”的曝光转化率异常偏低——原来是按钮在移动端被折叠到了首屏之外。产品团队依据埋点热力图迅速调整布局,转化率恢复并提升了 8%。

Python 演示

python78 行
import randomfrom collections import Counter  class MonitorSDK:    """极简版前端监控 SDK 模拟器"""     def __init__(self, sample_rate=0.3, batch_size=4):        self.sample_rate = sample_rate        self.batch_size = batch_size        self.buffer = []        self.batch_count = 0        self.error_fingerprints = Counter()        self.sent_events = 0     def should_sample(self, event_key):        """哈希采样: 同一事件要么全采要么全不采"""        digest = sum(ord(ch) for ch in event_key) % 1000        return digest < self.sample_rate * 1000     def capture_error(self, error_type, message, stack):        event = {            "type": error_type,            "message": message,            "stack": stack,            "time": 0,        }        if not self.should_sample(error_type + ":" + message):            return        self.buffer.append(event)        fingerprint = "|".join(stack.split("\n")[:3])        self.error_fingerprints[fingerprint] += 1        self._flush_if_needed()     def capture_performance(self, metric_name, value):        self.buffer.append({            "type": "perf",            "metric": metric_name,            "value": value,            "time": 0,        })        self._flush_if_needed()     def _flush_if_needed(self):        if len(self.buffer) >= self.batch_size:            self.flush()     def flush(self):        if not self.buffer:            return        payload = {"batch_id": self.batch_count, "events": self.buffer}        self.batch_count += 1        self.sent_events += len(self.buffer)        print("[上报] batch_id=%d 条数=%d" % (payload["batch_id"], len(self.buffer)))        self.buffer.clear()     def aggregate(self):        print("=== 错误聚合 Top3 ===")        for fingerprint, count in self.error_fingerprints.most_common(3):            print("指纹(堆栈前3帧): %s" % fingerprint)            print("  出现次数: %d" % count)  if __name__ == "__main__":    sdk = MonitorSDK(sample_rate=0.3, batch_size=4)    error_stacks = [        "TypeError: x is not a function\n"        "    at handleClick (app.js:120)\n"        "    at HTMLButtonElement.<anonymous> (app.js:88)",        "ReferenceError: foo is not defined\n"        "    at init (app.js:45)\n"        "    at main (app.js:10)",    ]    for i in range(20):        sdk.capture_error("js_error", "用户操作触发错误 %d" % i, error_stacks[i % 2])        sdk.capture_performance("lcp", round(random.uniform(1.5, 4.2), 2))    sdk.aggregate()    print("已上报事件总数: %d (采样率 %.0f%%)" % (sdk.sent_events, sdk.sample_rate * 100))
目的:模拟前端监控 SDK 的哈希采样、批量上报与错误聚合流程,演示一条“采样 → 缓冲 → 上报 → 聚合”的完整数据管道。
  1. digest = sum(ord(ch) for ch in event_key) % 1000把事件关键信息映射成 0~999 的哈希值,决定这条数据是否被采样
  2. fingerprint = "|".join(stack.split("\n")[:3])取堆栈前 3 行拼接成错误指纹,相同指纹视为同一错误
  3. self.error_fingerprints[fingerprint] += 1用 Counter 统计每个指纹出现的次数,相当于错误去重
  4. self._flush_if_needed()每次采集后检查缓冲区,满 batch_size 就触发送
  5. self.buffer.clear()发送完成后清空缓冲队列,避免重复上报
  6. self.error_fingerprints.most_common(3)聚合出出现频次最高的三个错误,就是“告警工单”的雏形

常见误区

误区我以为 window.onerror 能捕获所有 JS 错误,只要写好它,线上任何异常都逃不过我的眼睛。

正解window.onerror 只能捕获“运行时错误”,但捕不到三类重要异常:Promise 中被 reject 却没有 catch 的(需要 unhandledrejection 事件)、资源加载失败(资源元素错误不冒泡,需要在捕获阶段监听 error)、以及被 try/catch 主动吞掉的错误。就像商场中控室装了烟感,但水浸和门禁报警是独立线路,只盯一处就会漏报。

为何常见:window.onerror 名字里带"error",让人误以为它就是所有错误的汇总入口;再加上多数应用中的错误确实是运行时错误,加深了这个误解。

误区sourceMap 打包时一起发上线,监控平台才能随时还原源码,这不是很方便吗?为什么要限制访问?

正解sourceMap 本质是完整源码的映射,任何人拿到它都能还原出几乎原样的代码,等于把公司业务逻辑暴露在公网。正确做法是:sourceMap 仅用于监控平台内部,用私有地址加 token 保护;或让 Sentry 在解析完堆栈后立即删除公网映射文件;或对映射地址做访问控制。

为何常见:刚接触监控时只想着“能定位问题”,忽略了安全模型。类比商场把监控录像公开播放,顾客隐私将荡然无存。

误区我把采样率设为 100%,认为只有全量数据才算“准确”,不然分析结论不可信。

正解统计意义上,样本量达到几千后误差已收敛到可忽略。100% 采样意味着更高的上传带宽、更多的存储成本、更大的服务端压力,还可能拖慢业务本身。哈希采样能保证同一用户行为连续,足以支撑绝大多数分析。

为何常见:直觉上“全量 = 精确”,这是对统计知识的直觉缺失,忽略了成本与收益的平衡。

误区我把告警阈值调得很低,错误率稍微波动就发通知,认为这样可以第一时间抓到任何问题。

正解阈值过低会导致告警风暴,工程师每天被大量低价值告警轰炸后很快麻木,真正的大故障反而不受关注。正确做法是设置“阈值 + 持续时间”双条件,并对告警分级,让紧急故障通过电话渠道打断值班人,一般故障只进日报。

为何常见:负责任的心态被误用为“越敏感越负责”,缺少对告警信噪比的设计经验。

误区我把 Sentry 接进页面就觉得监控做完了,错误会自动定位、自动修复,团队可以高枕无忧。

正解Sentry 是“监控工具”而非“救火机器人”。它帮你采集、聚合、展示,但 sourceMap 上传、release 配置、issue 治理、告警规则、定期复盘都需要人工维护。装好摄像头还要有人盯着屏幕才有意义。

为何常见:Sentry 的自动化能力(自动捕获、自动聚合)给了团队“全自动”的错觉,忽略了监控平台的日常运营与治理工作。

面试题

Q1. 下列哪个 API 可以捕获 Promise 中未被 catch 的 rejection?

单选题 · easy

  • A.捕获全局同步运行时错误
  • B.捕获 Promise 未处理异常← 正确答案
  • C.捕获资源加载失败事件
  • D.捕获所有用户点击事件

答案:B。unhandledrejection 事件专门处理 Promise 链中被 reject 却无人 catch 的“孤儿异常”。window.onerror 与 error 监听只能捕获同步运行时错误和部分资源错误,与 Promise 异常无关。

Q2. 压缩混淆后的 JS 报错堆栈无法直接定位源码,通常用什么技术还原?

单选题 · mid

  • A.Babel 语法转译工具
  • B.sourceMap 映射还原← 正确答案
  • C.Webpack 模块打包器
  • D.浏览器开发者工具

答案:B。sourceMap 记录了压缩代码与原始代码的行列映射关系,监控平台拿到报错堆栈后,通过 sourceMap 反查即可还原出源码位置。Babel 是转译工具、Webpack 是打包工具,都不负责错误还原。

Q3. 下列哪些属于 Web Vitals 核心指标?

多选题 · mid

  • A.LCP 最大内容绘制← 正确答案
  • B.FID 首次输入延迟← 正确答案
  • C.CLS 累计布局偏移← 正确答案
  • D.TTFB 首字节到达

答案:ABC。Web Vitals 三大核心指标是 LCP、FID、CLS,分别衡量加载速度、交互响应与视觉稳定性。TTFB 是辅助诊断指标,不属于三大核心之列。

Q4. “顾客动线追踪”对应前端监控中的哪类技术?

单选题 · easy

  • A.错误监控体系
  • B.性能监控指标
  • C.用户行为埋点← 正确答案
  • D.告警通知服务

答案:C。用户行为埋点记录点击、浏览、曝光等行为轨迹,正是“顾客动线”的数字化;错误监控关注异常,性能监控关注快慢,告警服务负责通知,都不记录用户行为路径。

Q5. 下列哪种上报方式最适合用户在关闭页面瞬间上报数据?

单选题 · mid

  • A.同步 XMLHttpRequest
  • B.navigator.sendBeacon← 正确答案
  • C.Image 像素上报
  • D.异步 fetch 请求

答案:B。sendBeacon 专为 unload 场景设计,页面关闭时也能可靠送达。而同步 XHR 会阻塞卸载流程、被浏览器标记为警告,fetch 与 Image 请求在页面关闭时常常被浏览器终止。

Q6. 某错误真实发生率为 2%,将随机采样率降到 10% 后,关于采样结果说法正确的有?

多选题 · hard

  • A.期望错误率仍约 2%← 正确答案
  • B.样本越多误差越小← 正确答案
  • C.错误率会变成 20%
  • D.误差符合统计规律← 正确答案

答案:ABD。随机采样是无偏的,期望观测到的错误率仍等于真实发生率;根据大数定律与中心极限定理,样本量增大时误差减小,误差分布服从统计规律。C 选项混淆了“采样率”与“错误率”,采样率只影响样本量,不改写真实比例。

Q7. 错误聚合(issue)通常依据什么将多条错误合并成一条?

单选题 · mid

  • A.依据用户 ID 分组
  • B.错误消息完全相同
  • C.依据堆栈指纹聚合← 正确答案
  • D.依据上报时间接近

答案:C。同一错误常因参数不同导致消息文本有差异,但堆栈结构高度相似。按堆栈指纹(stack fingerprint)聚合最可靠,能把“同一个 bug 的不同变体”归为一个 issue。用户 ID 与时间都不是判断错误本质的依据。

Q8. 下列哪项是 Sentry 的核心作用?

单选题 · easy

  • A.压缩前端 JS 代码
  • B.收集聚合线上异常← 正确答案
  • C.自动修复所有缺陷
  • D.替代后端数据库

答案:B。Sentry 是开源错误监控平台,核心能力是收集、聚合、展示线上异常并辅助告警。它不负责压缩代码,也不能自动修复 bug,更不是数据库的替代品。

Q9. 关于 img/script 等资源加载错误,以下说法正确的有?

多选题 · hard

  • A.会被 onerror 捕获
  • B.需捕获阶段监听← 正确答案
  • C.可用 Performance 判断← 正确答案
  • D.无法被任何方式感知

答案:BC。资源加载错误不冒泡,window.onerror 捕获不到,只能在 capture 阶段用 addEventListener('error', fn, true) 监听;Performance API 的资源条目(resource timing)也能辅助判断加载是否失败。D 显然错误——资源错误有多种感知途径。

Q10. 某团队将告警阈值从“错误率 > 1% 触发”改为“错误率 > 2% 触发”,最可能产生的效果是?

单选题 · extreme

  • A.告警数量会成倍上升
  • B.告警减少漏掉轻微异常← 正确答案
  • C.错误率会自动下降
  • D.对告警没有任何影响

答案:B。阈值从 1% 提高到 2%,意味着更多低危错误被过滤,告警数量会减少,但轻微但持续的异常可能被漏报。这是灵敏度与噪音之间的权衡,A 恰好说反了,C 中错误率是客观指标不会因阈值改变而自动变化。