为什么做这次实验
我以前接触过 FCP、TTI 等性能指标,但很少真正打开 Chrome DevTools 的 Performance 面板录制页面,也没有完整跑过一次 Lighthouse、Network、Performance、修改和复测的流程。
开始前还有两个认识需要纠正:
- TTFB 不是 LLM 专属指标。在 Web 中,TTFB(Time to First Byte)表示从请求开始到收到响应第一个字节的时间;LLM 更常说的是 TTFT(Time to First Token)。二者都在描述“第一次响应”,但对象和测量边界不同。
- 本次使用的是 Lighthouse,不是图片管理软件 Lightroom。
这篇不是完整的网站性能审计,也不证明我已经掌握了前端性能工程。它只记录一次能够复现的学习实验:先测量 QQsNote 首页,再提出一个小假设,做一处改动,最后检查改动到底改变了什么。
实验对象、环境与证据边界
实验对象是已发布的 QQsNote 首页:
1 | https://qqstone.github.io/qqsnote/ |
线上测量环境:
| 项目 | 本次设置 |
|---|---|
| 日期 | 2026-07-27 至 2026-07-28 |
| 浏览器 | Google Chrome 149.0.7827.53 |
| 页面模式 | Desktop |
| Network throttling | No throttling |
| CPU throttling | No throttling |
| Network 缓存 | Disable cache |
| 浏览器扩展 | 干净基线使用无痕窗口,扩展关闭 |
这些设置适合第一次认识工具,但不代表真实用户环境。桌面设备、无降速和日本网络节点(指 GitHub Pages CDN 边缘节点)都会影响结果;Lighthouse 分数和加载时间只能解释这几次实验,不能直接当成网站长期 SLA。
第一步:用 Lighthouse 建立基线
Lighthouse 的 Performance 审计会在受控条件下重新加载页面,计算 FCP、LCP、TBT、CLS、Speed Index 等指标,并给出综合分数和可能的优化方向。它适合建立基线、比较改动前后和发现排查入口,但不能单独证明某条建议就是性能问题的根因。
我先用同一 Chrome 环境连续运行三次 Desktop Performance 审计:
| 运行 | Performance | FCP | LCP | TBT | CLS | Speed Index |
|---|---|---|---|---|---|---|
| 1 | 97 | 0.41 s | 0.49 s | 0 ms | 约 0 | 1.92 s |
| 2 | 96 | 0.94 s | 0.96 s | 0 ms | 约 0 | 1.56 s |
| 3 | 96 | 0.97 s | 0.97 s | 0 ms | 约 0 | 1.58 s |
三次结果没有完全相同。第 1 次 FCP 和 LCP 明显更快,但 Speed Index 反而更慢。这说明即使在同一台机器上,单次 Lighthouse 数字也有波动。我选择更接近中间结果的第 2 次作为截图,而不是挑分数最高的一次。
这张图先看五项指标,不需要一开始展开所有建议:
- FCP 回答页面第一次绘制内容的时间。
- LCP 回答主要内容完成绘制的时间。
- TBT 是实验室环境中主线程阻塞的辅助指标。
- CLS 关注非预期布局偏移。
- Speed Index 估算视口内容逐步呈现的速度。
我过去熟悉的 TTI(Time to Interactive)仍可能出现在 Lighthouse 的审计数据中,但已经不是当前报告顶部的主要评分指标。这里不再围绕 TTI 判断页面性能。
这次 Lighthouse 得分不错,但报告同时提示缓存生命周期、字体显示、DOM 规模和强制重排等候选问题。它们只是继续调查的入口,不等于应该把每一项都立即“修到绿色”。
一个无效的第一次录制:扩展也会进入性能数据
第一次打开日常使用的 Chrome 录制时,Network 底部显示约 3.7 MB transferred,Performance 的 1st/3rd party 汇总里还出现了“沉浸式翻译”和 React Developer Tools。
图中“沉浸式翻译”占用了约 596.5 ms 主线程时间,Network 里还有一个约 3.3 MB 的 content_main.js。这些资源由浏览器扩展注入,不属于 QQsNote。如果直接根据这次录制优化网站,我会把扩展成本错算到站点头上。
因此后面的 Network 和 Performance 数据都改用无痕窗口重新录制。这个失败比记住一个分数更有价值:性能实验首先要控制环境,否则工具给出的真数据也可能回答错问题。
第二步:用 Network 理解 TTFB
在无痕窗口中打开 Network,勾选 Disable cache,清空请求后刷新页面。这次列表里不再有翻译扩展脚本:
本次截图的底部汇总为:
| 项目 | 结果 |
|---|---|
| 请求数 | 14 |
| Transferred | 246 kB |
| Resources | 741 kB |
| DOMContentLoaded | 1.13 s |
| Load | 1.47 s |
| Finish | 1.64 s |
Transferred 和 Resources 不相等并不矛盾。前者接近实际网络传输量,后者更接近资源内容解压后的大小。主文档这一行显示约 94.6 kB,而生成的 HTML 原始内容约为 440 kB,主要差异来自传输压缩。
点击第一行 qqsnote/ 主文档,再切换到 Timing:
这一次的时间分解是:
| 阶段 | 时间 |
|---|---|
| Queueing | 1.05 ms |
| Stalled | 0.48 ms |
| Request sent | 0.19 ms |
| Waiting for server response | 447.50 ms |
| Content Download | 70.14 ms |
| Total | 519.35 ms |
DevTools 中的 Waiting for server response 是理解 TTFB 的关键部分:请求已经发出,但响应第一个字节还没有到达。它可能包含网络往返、CDN 和服务端处理等成本,单凭这一项不能断言“后端慢”。
对静态托管在 GitHub Pages 的 QQsNote 来说,本次 447.50 ms 也只是当前节点和当前请求的一次观测。要判断真实用户的 TTFB,需要长期的 field data,而不是这一张截图。
第三步:第一次录制 Performance
DevTools Performance 是手动录制与分析面板。它用时间轴展示页面加载期间的网络请求、帧、主线程任务、布局和绘制,适合继续定位“时间具体花在哪里”。它不像 Lighthouse 的 Performance 审计那样给出综合性能分数:Lighthouse 用于发现信号,DevTools Performance 用于查看执行细节和验证原因。
接着在无痕窗口打开 Performance,使用 Record and reload,等待页面稳定后停止:
我先只看四个区域:
- 顶部 Overview 用于确定主要活动发生在哪个时间段。
- Network 轨道显示资源请求和页面加载的关系。
- Main 轨道显示脚本、样式计算、布局和绘制任务。
- 底部 Summary 用来查看选中范围内各类工作的累计时间。
这次录制显示 LCP 为 1.70 s、CLS 为 0。在约 3.75 s 的选中范围内,Summary 记录了约 317 ms Rendering、79 ms Scripting、79 ms System、25 ms Painting 和 20 ms Loading。
这并不意味着“渲染就是唯一瓶颈”。Performance 左侧同时提示 Optimize DOM size,干净 CDP 采集还记录到首页约有 12,745 个元素、268 个 <pre> 和 156 个 <table>。这些数字把调查方向指向了首页内容结构:为什么一个博客列表页包含这么多正文节点?
从证据提出一个最小优化假设
查看 Hexo 生成结果后,原因很直接:NexT 在文章没有 description 或 <!-- more --> 时,会把完整正文放进首页。当前首页一次展示 10 篇文章,因此大量代码块和表格也被一起输出。
优化前,《Flow Graph 入门:用 TypeScript 实现工业视觉流程执行器》在首页生成的 <article> 片段为 136,972 B;设置摘要后,该片段为 2,969 B,差值正好是后文实测的 134,003 B。我提出的假设是:
如果只给这篇文章增加
description,NexT 会在首页显示摘要和“阅读全文”,从而减少首页 HTML 与 DOM 内容;详情页仍保留完整正文。
改动只涉及 front matter:
1 | description: 用 TypeScript 实现一个带类型端口、拓扑校验、执行追踪和安全检查的最小工业视觉 Flow Graph,理解 DAG 执行器的核心边界。 |
这个假设没有承诺 Lighthouse 分数一定上升。它首先应该证明两件更确定的事:生成的首页变小,详情页内容不丢失。
本地前后对比
线上 GitHub Pages 会受到网络和缓存影响,因此代码改动的前后对比统一在本地完成。两次都使用相同源码组成、相同 Hexo 命令和相同页面,只改变 Flow Graph 文章的 description。
本次对比优先记录构建产物和 DOM 内容的确定性变化。浏览器毫秒级时间会随机器负载波动,不用一次更快的数字证明用户体验已经提升。
先看每次干净构建都能重复得到的结果:
| 项目 | 优化前 | 优化后 | 变化 |
|---|---|---|---|
| 首页生成 HTML | 424,364 B | 290,361 B | -134,003 B(-31.6%) |
| 首页文章数 | 10 | 10 | 0 |
| 首页代码块 | 216 | 180 | -36 |
| 首页表格 | 124 | 104 | -20 |
| HTML 元素标签计数 | 11,905 | 7,052 | -4,853 |
| Flow Graph 详情页 | 170,319 B | 169,948 B | -371 B |
首页文章数没有变化,说明前后页面组成一致。代码块、表格和标签减少,是因为 Flow Graph 完整正文不再进入首页。详情页少量字节变化来自明确的 description 替换了自动生成的描述;正文中的 TypeScript 示例和学习目标仍然存在。
我还用相同的 Chrome、禁用缓存、网络和 CPU 均未降速的设置,各录制了一次本地页面:
| 浏览器观测 | 优化前 | 优化后 | 变化 |
|---|---|---|---|
| DOM 元素数 | 12,137 | 7,246 | -4,891 |
| DOMContentLoaded | 494.5 ms | 360.3 ms | -134.2 ms |
| FCP | 716 ms | 588 ms | -128 ms |
| LCP | 1,216 ms | 1,088 ms | -128 ms |
| 最长任务候选 | 138 ms | 73 ms | -65 ms |
浏览器 DOM 元素数与直接统计 HTML 标签的数值不完全相同,因为浏览器解析、主题脚本和 DOM 规范化也会影响最终节点。两种方法都显示了约四成的元素缩减。
时间数据的方向支持“少解析和渲染大量正文节点会减轻首页负担”这个假设,但每种状态只录制了一次,差异也可能受到机器调度影响。因此本次能确定证明的是 HTML 和 DOM 内容显著减少、详情页保持完整;不能据此声称所有用户的 LCP 都会稳定减少 128 ms。
这次实验真正学会了什么
完成这次实验后,我至少能独立完成下面这条小闭环:
1 | Lighthouse 建基线 |
比指标本身更重要的是三个边界:
- TTFB 是 Web 请求指标;LLM 首 Token 常用 TTFT。
- Lighthouse 给出候选问题和实验室分数,不直接替我决定优化优先级。
- Performance 记录的是真实活动,但浏览器扩展、缓存和录制范围会改变它回答的问题。
这篇也暴露了我的下一层缺口:我已经能读懂一次页面加载的概览,但还不能熟练从复杂火焰图中完成函数级归因,也没有做移动端限速或真实用户监控。
下一步
下一次只重复同一个实验,但把 Lighthouse 和 Performance 切换到移动端或 Slow 4G / CPU slowdown。目标不是再扩充一份性能名词表,而是观察同一个页面在资源受限时,主导问题是否发生变化。