在 mdn/PerformanceNavigationTiming 中可以看到所有的时间戳属性,但是做性能优化核心并不单单获知时间戳名,而是时间戳代表什么,怎么利用时间戳判断前端性能好坏和问题来源,进一步地说,就是找到需要关注的时间戳和时间段
数据获取
const observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => {
console.log(entry);
});
});
observer.observe({ type: 'navigation', buffered: true });
同事件类型时间段
如果时间戳名类似于 XXXEnd、XXXStart,那么这是事件型的时间戳,分别代表事件的开始和结束,二者之间的差值就是其耗时,比如:
- 重定向时间 redirectEnd - redirectStart
- TCP 连接 connectEnd - connectStart
- DNS 查询 domainLookupEnd - domainLookupStart
- 内容传输 responseEnd - responseStart
并不是所有的时间戳都一定有对应开始和结束,比如存在 workStart 代表 serviceWorker 启动,但是不存在 workEnd 代表结束,比如存在 fetchStart 代表请求开始,但是没有 fetchEnd 来表示请求结束
三大核心指标
前人总结经验,有三个核心指标和性能优化关系较大
- 首字节 responseStart - fetchStart
- DOM Ready domContentLoadedEventEnd - fetchStart
- 页面完全加载 loadEventStart - fetchStart
不难观察出一点,三个指标都和 fetchStart 相关,因为 fetchStart 代表请求开始
首字节
- 首字节时间 = TTFB = responseStart - fetchStart
- 在 mdn/TTFB 中写明了 TTFB 包括 DNS、TCP、TLS,所以 TTFB 的时间起点应该是 fetchStart,而不是 requestStart
- 部分资料会提到 TTFB 的时间起点是 requestStart,这个可能是 中文mdn 误导
- 怀疑翻译导致的,fetchStart 被翻译成请求开始,然后又被理解为 requestStart
mdn 关于 TTFB 原文
Time to First Byte (TTFB) refers to the time between the browser requesting a page and when it receives the first byte of information from the server. This time includes DNS lookup and establishing the connection using a TCP handshake and TLS handshake if the request is made over HTTPS.
DOM 解析完成
-
DOM Ready = HTML解析完成时间 = domContentLoadedEventEnd - fetchStart
-
domContentLoadedEvent 简称 dcl,是早年前端性能优化的重点
-
domInteractive、dcl、domComplete 的关系
-
执行顺序:dominteractive、defer script、dcl、加载资源、domComplete
-
async script 不保证加载和执行顺序,自然不绑定时间戳
-
dom 时间戳存在和 document.readyState 的对应关系,是曾经 dom 时间戳的判断方法
-
dom 解析开始时间
-
一般认为约等于 responseEnd
-
存在流式解析时,可能早于 responseEnd
-
同样的,dom 解析时间可以理解为 domInteractive - responseEnd
-
同步脚本阻塞可能推迟这个时间,同时 HTML Preload Scanner 让部分资源请求早于 domInteractive
-
如果有 async、defer的话,其可能会在 domInteractive 之后才执行
页面完全加载
- 页页面完全加载 loadEventStart - fetchStart
- 对应的,资源加载耗时就是 loadEventStart - domContentLoadedEventEnd
- 值得说的是,其实 loadEventStart - domComplete 约等于 0,也就是说资源加载主要是 domComplete - domContentLoadedEventEnd
当前版本三大核心指标意义有所下降
用户感知 ≠ 技术事件
-
用户只关心“最快能看到可交互内容”,即 FP、FCP、LCP;
-
这些指标往往发生在 dom 尚未完成、甚至 js、css 还没下载完的阶段;
-
而 DOM Ready 发生时,可能首屏早就渲染好了,继续优化它意义有限
SPA / 渐进式渲染弱化了“整页”概念
-
SPA / 渐进式渲染弱化了“整页”概念
-
单页应用首帧是一张空壳,后续路由切换全靠 js 动态拼装 dom;
-
首次包 + 关键资源 才是瓶颈,DOM Ready 只表示“外壳”好了,业务模块可能还没下载;
HTTP/2、HTTP/3、Service Worker 让后端首字节 & 网络栈并行化
-
过去 DNS+TCP+TLS 串行耗时大,TTFB 影响明显;
-
现在多路复用、连接复用、预连接、预加载把首字节提前
-
TTFB 本身也不是“性能瓶颈”而是变成了“网络可用性”,被用作“网络链路 + 服务器处理”健康度报警
http 缓存相关
http 缓存存在且命中的情况下
-
responseEnd - fetchStart 约等于 0
-
transferSize = 0 强缓存,transferSize 很小是协商缓存
-
无缓存的时候可能 transferSize > encodedBodySize(相应头)
-
一般谈论 navigation 时指 html 文件,而 html 文件不做缓存,如果是类似 PerformanceResourceTiming 涉及其他资源,才会出现缓存
如果 serviceworker 命中缓存也有类似情况(不考虑回源、内部处理耗时)