4、Resource Timing:分析静态资源(JS、CSS、图片)的加载瀑布图

4.1 瀑布图到底在告诉我们什么?

每次打开 Chrome DevTools 的 Network 面板,你都会看到那一排排花花绿绿的条形图。说实话,我刚开始做前端那会儿,也就看看「哪个文件加载慢」,然后随手加个 async 完事。后来被一个线上性能事故狠狠教育了一顿——一个 200KB 的 JS 文件,加载时间看起来正常,但页面就是卡了 3 秒才可交互。

嗯,问题就出在「看起来正常」这四个字上。瀑布图的每一段颜色,其实都藏着一段故事。

核心认知:Resource Timing API 能精确告诉你每个资源从「发起请求」到「下载完成」的每一个阶段耗时。这不是玄学,是实打实的毫秒级数据。

4.2 拆解一个请求的生命周期

一个静态资源的加载,说白了就是下面这几个阶段:

  1. DNS 查询:把域名解析成 IP。我见过一个项目,DNS 解析就占了 800ms,原因是用了慢 DNS 服务商。
  2. TCP 连接:三次握手。HTTP/2 可以复用连接,这里能省不少时间。
  3. TLS 协商:HTTPS 的加密握手。嗯,这一步在移动端尤其慢。
  4. 请求发送:浏览器把请求头发出去。通常很快,但如果你有大量 Cookie,这里会变慢。
  5. 等待(TTFB):服务器处理请求并返回第一个字节。这是后端性能的照妖镜。
  6. 内容下载:接收响应体。带宽和文件大小决定一切。

你想想看,如果某个 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,就是你手里最趁手的那把尺子。