88 lines
3.7 KiB
Markdown
88 lines
3.7 KiB
Markdown
---
|
||
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<typeof setTimeout> | 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 分位对比(数据以实测为准)。”
|