资源加载过程的详细性能信息
基于 PerformanceResourceTiming
对象对页面中某个资源加载过程的详细性能信息进行采集与封装,并结合了计算机网络中的请求生命周期进行度量。
export function observeEvent():void{const type="resource";const entryHandler=(list:PerformanceObserverEntryList,observer:PerformanceObserver):void=>{const data=list.getEntries();for(const entry of data){ observer && observer.disconnect();// Cast to PerformanceResourceTiming to access resource-specific propertiesconst resourceEntry = entry as PerformanceResourceTiming;const reportData = {name: entry.name, // 资源的名字type: 'performance', // 类型subType: entry.entryType, //类型sourceType: resourceEntry.initiatorType, // 资源类型duration: entry.duration, // 加载时间dns: resourceEntry.domainLookupEnd - resourceEntry.domainLookupStart, // dns解析时间tcp: resourceEntry.connectEnd - resourceEntry.connectStart, // tcp连接时间redirect: resourceEntry.redirectEnd - resourceEntry.redirectStart, // 重定向时间ttfb: resourceEntry.responseStart, // 首字节时间protocol: resourceEntry.nextHopProtocol, // 请求协议responseBodySize: resourceEntry.encodedBodySize, // 响应内容大小responseHeaderSize: resourceEntry.transferSize - resourceEntry.encodedBodySize, // 响应头部大小transferSize: resourceEntry.transferSize, // 请求内容大小resourceSize: resourceEntry.decodedBodySize, // 资源解压后的大小startTime: performance.now(),};// TODO:发送数据} }const observer=new PerformanceObserver(entryHandler);observer.observe({type:type,buffered:true})
}
✅ 目标:
梳理资源加载过程中各阶段的网络开销与性能指标,并解释这段代码中的每个字段,按照计算机网络请求-响应的真实顺序排列分析。
🧩 一、资源加载的网络过程(结合指标顺序)
我们将其还原为浏览器加载资源时实际的网络执行流程,并将你 reportData
中的字段标注进来:
⏱️ 1. redirect
- 重定向时间(HTTP 状态 3xx)
redirect = redirectEnd - redirectStart
- 表示该资源在跳转链中的耗时;
- 如从
http://a.com
→https://a.com
。
🌐 2. dns
- DNS 查询时间
dns = domainLookupEnd - domainLookupStart
- 浏览器将域名(如
example.com
)解析为 IP 地址; - 若启用了本地缓存,时间可能为 0。
🔐 3. tcp
- TCP 握手 + TLS 握手时间
tcp = connectEnd - connectStart
- 包括三次握手 + TLS 握手(如果是 HTTPS);
- 若启用
keep-alive
,这部分也可能为 0。
📥 4. ttfb
- 首字节时间(Time to First Byte)
ttfb = responseStart
- 表示浏览器开始接收到服务器的第一个字节的时间点;
- 包括请求排队、后端处理、网络传输;
- 越小越好,反映服务器响应速度。
📦 5. responseHeaderSize
& responseBodySize
responseHeaderSize = transferSize - encodedBodySize
responseBodySize = encodedBodySize
- Header 是响应头;
- Body 是响应内容的压缩大小;
- transferSize 包括头 + 压缩的 body + 其他元数据;
- 通过这些可以分析资源是否压缩,是否缓存命中(有时大小为 0)。
📊 6. resourceSize
- 解压后的真实内容大小
resourceSize = decodedBodySize
- 如 gzip 压缩后资源只有 100KB,但解压后为 300KB;
- 用于真实数据占用的评估。
🔍 7. protocol
- 请求使用的协议
protocol = nextHopProtocol
- 可能值有:
h2
、http/1.1
、http/3
等; - 可以用来分析 HTTP/2 多路复用是否生效。
⌛ 8. duration
- 整体加载耗时
duration = entry.duration
- 完整的资源加载耗时:从发出请求到下载完全部内容;
- 等于:
responseEnd - startTime
。
📍 9. startTime
- 当前时间采集点
startTime: performance.now()
- 当前调用采集逻辑的相对时间(从 navigationStart 开始);
- 可用于排序和关联其他性能事件(如 paint)。
🧠 二、附加字段(非网络指标)
name = entry.name
type = 'performance'
subType = entry.entryType
sourceType = entry.initiatorType
name
:资源的 URL;type
:标记类型(用于上报分类);subType
:此处为'resource'
;sourceType
:如script
、img
、css
、fetch
等,用于判断加载来源。
📈 三、浏览器加载资源完整流程图
✅ 总结版字段梳理(顺序)
字段名 | 说明 | 来源 |
---|---|---|
redirect | 是否跳转及跳转耗时 | HTTP 3xx |
dns | 域名解析耗时 | DNS |
tcp | 建立连接耗时(含 TLS) | TCP/TLS |
ttfb | 首字节时间(服务器响应速度) | HTTP |
responseHeaderSize | 响应头大小 | HTTP |
responseBodySize | 响应体大小(压缩) | HTTP |
resourceSize | 解压后真实大小 | 应用层 |
duration | 整体耗时 | 综合 |
protocol | HTTP 协议版本 | 网络 |
startTime | 当前采集点时间 | 监控逻辑 |
sourceType | 资源来源 | 性能入口 |
subType | 资源类型(resource) | 性能入口 |
浏览器加载资源的全过程
🧩 一、浏览器加载资源的全过程(从点击链接到资源加载完成)
我们以加载一个资源(如图片、脚本或 CSS)为例,步骤如下:
✅ 步骤 1:构建请求 URL
浏览器在解析 HTML、JS 时遇到资源引用(如 <img src="...">
、<script>
),会开始构造请求 URL。
✅ 步骤 2:查找缓存(非网络部分)
- Memory Cache / Disk Cache / Service Worker Cache
- 若命中,直接返回缓存内容,跳过网络阶段;
- 否则继续发起网络请求。
🌐 网络部分(计算机网络角度)
✅ 步骤 3:重定向(可选)
redirect = redirectEnd - redirectStart
- 若 URL 被服务器重定向(如 http → https),浏览器首先跟随跳转;
- 每次重定向都重新走 DNS → TCP → 请求 → 响应;
- 过多重定向会严重影响性能(应控制在 < 3 次)。
✅ 步骤 4:DNS 解析
dns = domainLookupEnd - domainLookupStart
- 浏览器将域名(如
img.cdn.com
)解析成 IP 地址; - 查询顺序:浏览器缓存 → 操作系统缓存 → 本地 hosts 文件 → DNS 服务器;
- 若使用了
DNS Prefetch
,此步耗时为 0。
✅ 步骤 5:TCP 建立连接(含 TLS)
tcp = connectEnd - connectStart
- 包括三次握手(TCP)+ TLS 握手(HTTPS);
- 如果开启 HTTP Keep-Alive,复用连接,此处耗时为 0;
- HTTP/2、HTTP/3 可复用一个连接,减少耗时。
✅ 步骤 6:发送 HTTP 请求 + 等待响应首字节(TTFB)
ttfb = responseStart
- TTFB (Time To First Byte):从请求发出到接收到服务器首字节;
- 反映服务器后端处理速度 + 网络延迟;
- 低 TTFB 是高性能服务的体现。
✅ 步骤 7:响应下载(Header + Body)
responseHeaderSize = transferSize - encodedBodySize
responseBodySize = encodedBodySize
transferSize
是传输的总字节数(头部+压缩内容);encodedBodySize
是压缩后的体积;decodedBodySize
是解压后的体积(真实内容大小)。
✅ 步骤 8:下载结束、解压资源
resourceSize = decodedBodySize
duration = entry.duration
duration
是整体耗时(从startTime
到responseEnd
);- 浏览器可能同时进行解码、缓存写入等操作;
resourceSize
反映资源实际内存占用。
🔍 二、与 Performance API 的字段对应关系表
网络阶段 | 指标名称 | 含义 | Performance 对应字段 |
---|---|---|---|
重定向 | redirect | 重定向耗时 | redirectEnd - redirectStart |
DNS 查询 | dns | 域名解析时间 | domainLookupEnd - domainLookupStart |
TCP/TLS | tcp | 连接耗时 | connectEnd - connectStart |
请求发出 → 首字节 | ttfb | Time to First Byte | responseStart |
响应传输 | responseBodySize | 压缩体积 | encodedBodySize |
响应头 | responseHeaderSize | Header 大小 | transferSize - encodedBodySize |
资源体积 | resourceSize | 解压后大小 | decodedBodySize |
整体耗时 | duration | 总体加载耗时 | entry.duration |
协议 | protocol | HTTP/1.1, HTTP/2… | nextHopProtocol |
🧠 三、实际示意图说明(Mermaid 类图)
我们用 Mermaid 的类图表示资源加载中的性能数据结构:
🧾 总结:开发中这些字段怎么用?
场景 | 指标用途 |
---|---|
网络慢? | 检查 DNS / TCP / TTFB 哪一步耗时高 |
CDN 优化 | 检查 protocol 是否为 HTTP/2 |
资源压缩 | 对比 encodedBodySize 和 decodedBodySize |
后端慢 | ttfb 偏大,说明服务响应慢 |
首屏加载慢 | 分析关键资源的 duration 是否超标 |