Performance API
Performance API 是浏览器提供给我们的用于检测网页性能的 API,它并不是一个孤立的 API,而是一组 API 的组合。主要包括:
- Resource Timing API:与网页资源(脚本、样式、图片等)加载相关的耗时信息,定义了接口 PerformanceResourceTiming。
- Navigation Timing API:从页面导航开始一直到 load 事件结束,中间经历过程的耗时信息。定义了接口 PerformanceNavigationTiming,此接口继承自 PerformanceResourceTiming 接口。
- Paint Timing:与网页绘制相关的耗时信息。定义了接口 PerformancePaintTiming。
上面三个接口,又都继承自 Performance Timeline API 中的 PerformanceEntry 接口,所以每个接口实例叫做 Entry。PerformanceEntry 中定义了四个基本的只读属性:name、entryType、startTime 和 duration。
为了方便理解,现在打开地址:www.w3.org/TR/performa…,调出控制台,复制下面的代码(来自 MDN)执行,就能看到网页从导航到显示中间的耗时统计信息。
// See: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEntry#Example
function print_PerformanceEntries() {
// Use getEntries() to get a list of all performance entries
var p = performance.getEntries();
for (var i=0; i < p.length; i++) {
console.log("PerformanceEntry[" + i + "]");
print_PerformanceEntry(p[i]);
}
}
function print_PerformanceEntry(perfEntry) {
var properties = ["name",
"entryType",
"startTime",
"duration"];
for (var i=0; i < properties.length; i++) {
// Check each property
var supported = properties[i] in perfEntry;
if (supported) {
var value = perfEntry[properties[i]];
console.log("... " + properties[i] + " = " + value);
} else {
console.log("... " + properties[i] + " is NOT supported");
}
}
}
// 打印网页
print_PerformanceEntries()
window 对象上暴露了一个 performance 属性,这个属性提供了 getEntries 方法,可以用来获取整个页面的性能实体列表(performance entries),这些实体对象中包含了从不同角度记录的耗时信息;接下来再对得到的结果使用 for 循环遍历出来。
下面是在我控制台上的打印结果:
导航阶段
本文只介绍导航阶段(也都是上面打印的第一条数据)的统计信息。其他两个按照下面同样的思路分析即可。
进入页面,首先统计的就是页面从导航一直到 load 事件结束的过程,这些信息都保存在了 PerformanceNavigationTiming 实例中。字段解释如下:
- name:对应地址栏输入的导航地址
- entryType 值为 navigation,表示这是一个 PerformanceNavigationTiming 实例
- startTime:开始时间(单位毫秒,精度到 0.0001 ms)
- duration: 导航过程耗费的时间
更加完整的信息可以通过使用 performance.getEntries()[0] 获得:
是不是有种似曾相识的感觉呢?最近有面试或者曾经有面试的同学,肯定有被问过“从输入 URL 到页面展示,这中间发生了什么?”的问题,而上面的流程正好对应整个过程。
PerformanceNavigationTiming 实例的属性解析
现在,我们就上面的流程,来一个个解析 PerformanceNavigationTiming 实例中所涉及到的各个属性的含义。
-
startTime: 开始导航的时间。加载新页面、当前页面卸载时会触发 unload 事件。如果当前页面有未提交的表单数据等情况,会弹出一个确认关闭框。点击确认后,导航流程开始。startTime 值几乎总为 0。
-
unloaStart、unloadEnd:对应页面 unload 事件,标记该事件的开始和结束时间。
-
redirectStart、redirectEnd:如果页面发生了重定向,redirectStart 表示重定向开始时间,redirectEnd 表示重定向结束时间。如果没有重定向,redirectStart、redirectEnd 值都为 0。
-
fetchStart:下一步,取浏览器本地缓存(强缓存,如果本地缓存过期,还有一个走协商缓存的过程)。fetchStart 表示开始取缓存时间。
-
domainLookupStart、domainLookupEnd:从域名到 IP 地址有一个 DNS 解析过程。domainLookupStart、domainLookupStart 分别标记解析开始和结束时间。
-
connnectStart、connectEnd、secureConnectEnd:得到 IP 地址,正式开始请求之前,进行 TCP 连接。connnectStart 记录连接的开始时间,如果使用的 https 协议,还有一个建立 STL 连接,得到会话密钥的过程,使用 secureConnectStart 字段记录。
-
requestStart:接下来发起真正的 HTTP 请求,构建请求头信息,携带 cookie 字段信息等。
-
responseStart、responseEnd:响应开始和结束时间(先接收响应头,再接收响应体)。
- 以上对应的是从发出请求到接收响应的整个过程,如果响应头 Content-Type 字段值为 text/html,那么从下一步开始就是页面渲染阶段了。
-
domInteractive、domContentLoadedEventStart、domContentLoadedEventEnd、domComplete:domInteractive、domComplete 可以对应到 document readystatechange 事件 上的 interactive、complete 值(document.readyState 属性的两个可用取值)。domContentLoadedEventStart、domContentLoadedEventEnd 则对应 document DOMContentLoaded 事件,标记事件的开始和结束时间。
-
loadStart、loadEnd:这里对应的是 load 事件(当页面资源(脚本、样式、图片、音视频、iframe 等)全部加载完成后),标记事件的开始和结束时间。
至此,梳理完成 PerformanceNavigationTiming 实例所有核心属性的含义。
实际使用
Cloudflare 公司 在自家的统计系统中,就使用了 PerformanceNavigationTiming 实例信息,对网页性能做了统计。展示效果如下:
- DNS (domainLookupEnd - domainLookupStart): DNS 查询话费的时间。如果是重用连接或是使用了本地 DNS 数据缓存的话,此值为 0。
- TCP (connectEnd - connectStart): 建立 TCP 连接花费的时间。如果是走 HTTPS 协议,中间还多一步 TLS 协商生成会话密钥的过程。
- Request (responseStart - requestStart): 从开始发起请求,到接收到第一个字节的响应数据,中间经历的时间。
- Response (responseEnd - responseStart): 从接受第一个字节的响应数据到接收最后一个字节的响应数据中间经历的时间,也可以认为是资源下载时间。
- Processing (domComplete - domInteractive): 渲染页面花费的时长。如果数值很大,那么你可能就要考虑去优化文档结构或是资源大小了。
- Load Event (loadEventEnd - loadEventStart): 当浏览器完成页面中所有的资源加载的时候,会触发一个 load 事件. 在这个阶段,你可以在事件处理函数中,添加额外的处理逻辑。
- Total Time: 上图中各项指标的花费时间总和。
参考链接
(完)