--- id: frontend.fe-testing-perf.scenario.perf-regression title: 性能治理:真实用户监控、定位慢页面、CI 性能预算和测试防回归 type: scenario domain: frontend stack: [fe-testing-perf, cicd] tags: [性能监控, RUM, Lighthouse CI, 性能预算, 回归测试, INP] level: intermediate prerequisites: [frontend.fe-testing-perf.web-vitals, frontend.fe-testing-perf.testing] est_hours: 2.5 related: [frontend.fe-testing-perf.interview, frontend.webpack.scenario.build-speed] week: [7] --- # 性能治理:真实用户监控、定位慢页面、CI 性能预算和测试防回归 ## 业务背景与问题 SaaS 客服工作台(Vue / React 单页应用):客户投诉“越用越卡”,坐席在工单列表和 AI 回复面板之间切换时明显卡顿;每次大促前临时优化,之后又退化;没人说得清哪个页面、哪类设备慢。 ## 约束 - 不能大规模重写。 - 坐席电脑配置参差不齐。 - 需要用数据向业务方说明优化效果。 ## 方案设计 1. **可观测**:上线 RUM 采集 LCP / INP / CLS + 页面路径 + 版本号 + 设备信息;按页面和版本看 75 分位;同时采集长任务(Long Animation Frames / Long Tasks API,以 MDN 为准)。 2. **定位**:从 INP 最差的页面入手,在性能面板录制,找到长任务的调用栈。常见发现: - 工单列表一次渲染上千行 → 虚拟列表; - AI 回复每个 token 重新渲染整个面板 → 批量合并更新 + 局部渲染; - 全局状态变化导致整页重新渲染 → 拆分状态、记忆化。 3. **防退化**: - CI 中对关键页面跑 Lighthouse(实验室数据)设置预算,超出则失败; - 产物体积预算; - 对“竞态、防抖、批量更新”等逻辑写单元 / 组件测试; - 每个版本对比 RUM 指标,退化告警。 4. **汇报**:用优化前后同类设备的 75 分位对比说明效果。 ## 关键代码 批量合并流式 token,降低渲染频率: ```ts export function createBatcher(flush: (text: string) => void, intervalMs = 50) { let buffer = ""; let timer: ReturnType | null = null; return { push(token: string) { buffer += token; timer ??= setTimeout(() => { // 一个时间窗口内的 token 合并成一次渲染 flush(buffer); buffer = ""; timer = null; }, intervalMs); }, end() { if (timer) clearTimeout(timer); if (buffer) flush(buffer); buffer = ""; timer = null; }, }; } ``` 防抖与竞态的组件测试:[examples/search-box](../examples/search-box/)。 ## 取舍 | 选择 | 优点 | 缺点 | | --- | --- | --- | | **RUM + 实验室预算(本方案)** | 既知道真实情况,又能在合并前拦截退化 | 需要搭建采集和看板 | | 只用 Lighthouse | 简单 | 与真实用户体验有差距,尤其是 INP | | 使用第三方性能监控平台 | 开箱即用 | 成本、数据合规(客服数据不能随便上报) | ## 易错点 - 上报数据中带了客户的敏感信息(URL 参数中的手机号、工单内容)。 - 只看平均值。 - 批量渲染的定时器在组件卸载时没有清理。 - 优化了实验室分数,真实 INP 没变化:交互卡顿往往在登录后的复杂页面,Lighthouse 默认测不到。 ## 面试怎么讲 > “先建立度量:线上采集 Web Vitals 按页面和版本看 75 分位,发现工作台的 INP 最差。用性能面板定位到两个长任务:工单列表全量渲染和 AI 回复逐 token 重渲染,分别改成虚拟列表和 50ms 批量更新。然后在 CI 加 Lighthouse 和体积预算、给关键交互逻辑写测试防止退化。效果用优化前后同类设备的 75 分位对比(数据以实测为准)。”