4、Resource Timing:分析静态资源(JS、CSS、图片)的加载瀑布图
4.1 瀑布图到底在告诉我们什么?
每次打开 Chrome DevTools 的 Network 面板,你都会看到那一排排花花绿绿的条形图。说实话,我刚开始做前端那会儿,也就看看「哪个文件加载慢」,然后随手加个 async 完事。后来被一个线上性能事故狠狠教育了一顿——一个 200KB 的 JS 文件,加载时间看起来正常,但页面就是卡了 3 秒才可交互。
嗯,问题就出在「看起来正常」这四个字上。瀑布图的每一段颜色,其实都藏着一段故事。
核心认知:Resource Timing API 能精确告诉你每个资源从「发起请求」到「下载完成」的每一个阶段耗时。这不是玄学,是实打实的毫秒级数据。
4.2 拆解一个请求的生命周期
一个静态资源的加载,说白了就是下面这几个阶段:
- DNS 查询:把域名解析成 IP。我见过一个项目,DNS 解析就占了 800ms,原因是用了慢 DNS 服务商。
- TCP 连接:三次握手。HTTP/2 可以复用连接,这里能省不少时间。
- TLS 协商:HTTPS 的加密握手。嗯,这一步在移动端尤其慢。
- 请求发送:浏览器把请求头发出去。通常很快,但如果你有大量 Cookie,这里会变慢。
- 等待(TTFB):服务器处理请求并返回第一个字节。这是后端性能的照妖镜。
- 内容下载:接收响应体。带宽和文件大小决定一切。
你想想看,如果某个 JS 文件加载慢,到底是慢在哪一步?没有 Resource Timing,你只能靠猜。有了它,你就能精准定位。
4.3 用代码拿到这些数据
浏览器提供了 performance.getEntriesByType('resource') 方法。我个人习惯在页面加载完成后,把关键资源的耗时打出来看看。
// 获取所有静态资源的加载信息
const resources = performance.getEntriesByType('resource');
resources.forEach(entry => {
// 只关注 JS、CSS、图片
if (!/\.(js|css|png|jpg|webp)$/i.test(entry.name)) return;
const timing = {
name: entry.name.split('/').pop(),
dns: entry.domainLookupEnd - entry.domainLookupStart,
tcp: entry.connectEnd - entry.connectStart,
tls: entry.secureConnectionStart ?
(entry.connectEnd - entry.secureConnectionStart) : 0,
ttfb: entry.responseStart - entry.requestStart,
download: entry.responseEnd - entry.responseStart,
total: entry.responseEnd - entry.startTime
};
console.table(timing);
});
小技巧:在控制台跑这段代码,你会看到每个资源各阶段的耗时。我曾经用这个方法发现一个图片的 TTFB 高达 1.2 秒,最后查出来是 CDN 回源配置有问题。
4.4 瀑布图实战分析:一个真实案例
我记得有一次帮一个电商团队做性能优化。他们的首页有个 banner 图,加载特别慢。用 Resource Timing 一查,数据是这样的:
| 阶段 | 耗时 (ms) | 占比 |
|---|---|---|
| DNS 查询 | 5 | 0.3% |
| TCP 连接 | 15 | 0.9% |
| TLS 协商 | 80 | 4.7% |
| TTFB | 950 | 55.9% |
| 内容下载 | 650 | 38.2% |
| 总计 | 1700 | 100% |
看到没?TTFB 占了 55.9%。这说明问题不在前端,而在服务器或者 CDN。后来一查,是图片没有做缓存预热,每次请求都要回源站拉取。优化方案很简单:提前把图片推到 CDN 节点上,TTFB 直接降到了 120ms。
避坑指南:我曾经遇到一个情况,某个 CSS 文件的 TTFB 只有 50ms,但总加载时间却要 2 秒。仔细一看,是下载阶段花了 1.9 秒。为什么?因为这个 CSS 文件没被压缩,原始大小 1.2MB。嗯,开启 Gzip 后,下载时间降到了 200ms。所以,别只看总时间,要拆开看每一段。
4.5 如何用瀑布图指导优化策略
不同的阶段,对应不同的优化手段。我整理了一个对照表,你可以直接拿来用:
| 瓶颈阶段 | 典型原因 | 优化方案 |
|---|---|---|
| DNS 查询过长 | DNS 服务商慢、域名过多 | 使用 dns-prefetch、减少域名数量 |
| TCP/TLS 过长 | 连接未复用、HTTPS 握手开销 | 启用 HTTP/2、使用 preconnect |
| TTFB 过高 | 服务器处理慢、CDN 未命中 | 优化后端接口、配置 CDN 预热 |
| 下载时间过长 | 文件太大、带宽不足 | 压缩(Gzip/Brotli)、图片 WebP、代码分割 |
4.6 自动化监控:把瀑布图变成报警
手动看瀑布图只能解决一时的问题。我建议你在项目中加上自动化监控。比如,当某个 JS 文件的 TTFB 超过 500ms 时,自动上报到监控系统。
// 简单的性能监控上报
window.addEventListener('load', () => {
const resources = performance.getEntriesByType('resource');
resources.forEach(entry => {
const ttfb = entry.responseStart - entry.requestStart;
const download = entry.responseEnd - entry.responseStart;
// 阈值判断
if (ttfb > 500) {
console.warn(`[性能告警] ${entry.name} TTFB 过高: ${ttfb}ms`);
// 上报到你的监控平台
// reportToMonitor({ name: entry.name, ttfb, download });
}
if (download > 2000) {
console.warn(`[性能告警] ${entry.name} 下载时间过长: ${download}ms`);
}
});
});
个人经验:我习惯把 Resource Timing 的数据和用户真实体验数据(比如 LCP、FID)关联起来看。举个例子,如果 LCP 指标变差了,我就去查对应时间点的图片资源加载瀑布图。这样能快速定位是「网络问题」还是「资源本身问题」。
4.7 总结一下
Resource Timing 就像给静态资源做了一次「全身体检」。你不需要记住所有 API 字段,但一定要学会看瀑布图的每一段颜色代表什么。下次再遇到「页面加载慢」的问题,别急着拍脑袋加缓存,先打开瀑布图,看看慢在哪一步。
说白了,性能优化就是「测量 - 定位 - 优化 - 再测量」的循环。而 Resource Timing,就是你手里最趁手的那把尺子。