详细分析 ▾
运行时依赖
版本
从所有任务技能中批量发布,去重处理
安装命令
点击复制技能文档
通过测量实际加载时间和网络活动来诊断性能问题。Playwright 已预装。只需使用测量脚本。
快速开始
此技能的目录中包含一个 measure.ts 脚本。找到它并运行:
# 测量页面(输出包含瀑布数据的 JSON) npx ts-node /measure.ts http://localhost:3000
# 测量 API 端点 npx ts-node /measure.ts http://localhost:3000/api/products
脚本与此 SKILL.md 文件位于同一目录。
理解输出
脚本输出包含以下 JSON 数据:
{
"url": "http://localhost:3000",
"totalMs": 1523,
"requests": [
{ "url": "http://localhost:3000/", "ms": 45.2 },
{ "url": "http://localhost:3000/api/products", "ms": 512.3 },
{ "url": "http://localhost:3000/api/featured", "ms": 301.1 }
],
"metrics": {
"JSHeapUsedSize": 4521984,
"LayoutCount": 12,
"ScriptDuration": 0.234
}
}
阅读瀑布图
requests 数组显示网络时间。寻找顺序模式:
错误(顺序 - 每个都等待前一个): /api/products |████████| 512ms /api/featured |██████| 301ms(在 products 之后开始) /api/categories |████| 201ms(在 featured 之后开始) 总计:1014ms
正确(并行 - 全部同时开始): /api/products |████████| 512ms /api/featured |██████| 301ms(同时开始) /api/categories |████| 201ms(同时开始) 总计:512ms(只是最慢的一个)
关键指标
| 指标 | 含义 | 红色警报 |
|---|---|---|
totalMs | 页面总加载时间 | > 1000ms |
JSHeapUsedSize | JS 使用的内存 | 随时间增长 |
LayoutCount | 布局重计算次数 | 每页 > 50 次 |
ScriptDuration | JS 执行时间 | > 0.5s |
需要关注的问题
| 症状 | 可能原因 | 修复方法 |
|---|---|---|
| 请求按顺序进行 | 顺序的 await 语句 | 使用 Promise.all() |
| 同一 URL 被请求两次 | 在缓存检查前获取 | 先检查缓存 |
| 响应开始前时间长 | 发送前有阻塞操作 | 使其异步/非阻塞 |
| LayoutCount 高 | 组件重新渲染 | 添加 React.memo、useMemo |
直接测量 API 端点
无需浏览器开销,快速测量 API 时间:
async function measureAPI(url: string) { const start = Date.now(); const response = await fetch(url); const elapsed = Date.now() - start; return { url, time_ms: elapsed, status: response.status }; }// 示例 const endpoints = [ 'http://localhost:3000/api/products', 'http://localhost:3000/api/products?cache=false', 'http://localhost:3000/api/checkout', ];
for (const endpoint of endpoints) { const result = await measureAPI(endpoint); console.log(${endpoint}: ${result.time_ms}ms); }
测量脚本的工作原理
脚本使用 Chrome 开发者工具协议(CDP)来拦截浏览器内部:
- Network.requestWillBeSent - 请求开始时触发的事件,我们记录时间戳
- Network.responseReceived - 响应到达时触发的事件,我们计算持续时间
- Performance.getMetrics - 返回 Chrome 的内部计数器(内存、布局、脚本时间)
这为你提供了与 Chrome DevTools Network 标签相同的数据,但是通过程序方式。
视觉稳定性测量
测量 CLS(累积布局偏移)
npx ts-node /measure-cls.ts http://localhost:3000
输出:
{
"url": "http://localhost:3000",
"cls": 0.42,
"rating": "poor",
"shifts": [
{
"value": 0.15,
"hadRecentInput": false,
"sources": [
{ "nodeId": 42, "previousRect": {...}, "currentRect": {...} }
]
}
]
}
CLS 阈值
| CLS 分数 | 评级 | 操作 |
|---|---|---|
| < 0.1 | 良好 | 无需操作 |
| 0.1 - 0.25 | 需要改进 | 审查偏移源 |
| > 0.25 | 差 | 立即修复 |
检测主题闪烁
npx ts-node /detect-flicker.ts http://localhost:3000
检测深色主题在加载前是否闪烁白色。在导航前设置 localStorage 主题,并在首次绘制时检查背景颜色。
准确的 CLS 测量
CLS 只测量视口内的偏移。折叠下方加载的内容不会贡献 CLS,直到你滚动。为了准确测量:
推荐的测试序列:
- 加载页面
- 等待 3 秒(让延迟加载的内容出现)
- 滚动到底部
- 等待 2 秒
- 触发 1-2 个 UI 操作(主题切换、筛选点击等)
- 等待 2 秒
- 读取最终 CLS
# 基本测量(可能会错过延迟内容的偏移) npx ts-node /measure-cls.ts http://localhost:3000
# 带滚动(捕获更多偏移) npx ts-node /measure-cls.ts http://localhost:3000 --scroll
为什么测量值会变化:
- 生产版本 vs 开发版本有不同的时序
- 视口大小影响偏移时"在视口内"的内容
- setTimeout 延迟在运行之间略有不同
- 网络条件影响内容加载时间
相对差异(修复前/后)比绝对值更重要。
常见 CLS 原因
| 偏移源 | 可能原因 | 修复方法 |
|---|---|---|
元素 | 缺少宽度/高度 | 添加尺寸或使用 next/image |
| 主题包装器 | 水合闪烁 | 在 React 之前使用内联脚本 |
| 骨架屏加载器 | 尺寸不匹配 | 使骨架与最终内容尺寸匹配 |
| 动态横幅 | 没有预留空间 | 为容器添加 min-height |
| 延迟加载的侧边栏 | 内容出现并推动主内容 | 用 CSS 预留空间或显示占位符 |
| 分页/结果栏 | 数据加载后出现 UI 元素 | 立即显示加载状态 |
| 字体加载 | 自定义字体导致文本回流 | 使用 font-display: swap 或预加载字体 |