性能监控 在前端一直是一个口头上备受关注但开发中又常被忽略的点, 毕竟不是每个开发者很容易就做到的事. 好在 html5 新增了 performance 特性, 它是 High Resolution Time API 的一部分, 目的在于获取到当前页面中与性能相关的信息, 以便帮助开发者直观感受页面性能及针对问题优化.
了解如何监控页面性能前, 我们先回顾几个指标:
(1)白屏时间: 页面被打开, 到首字节渲染呈现所需的时间.
(2)首屏时间: 首屏内容渲染完成所需的时间.
(3)下载时间(HTTP 请求耗时): 页面所需资源从服务器上下载完成所需的时间.
(4)DOM 树解析时间: 资源下载完成到页面构建展示出来所需的时间.
...
这些信息都如何获取? 在此标准之前, 也有一些手段可以实现, 但 H5 的 performance 直接来源于浏览器, 与手工 Date.time,Cookie 等对比, 使用上更方便, 数据上更准确.
# Performance 属性
关于 performance 属性, 建议读者自己在工具编辑器上直接打印出来看看更能真切的体会该接口. 本文主要介绍 timing 属性, 对其他内容感兴趣的同学, 可以 戳这里
.timing(只读): 对象; 包含了延迟相关的性能信息.
.navigation(只读): 对象; 包含了指定的时间段里发生的操作相关信息, 包括页面是加载还是刷新, 发生了多少次重定向等等.
.timeOrigin(只读): 即将失效. 用于返回性能测量开始时的高精度时间戳.
.memory: 由 Chrome 拓展的非标准属性, 用于返回基本内存的使用情况. 注意非 Chrome 不支持.
- # Performance.timing 只读
- const PerformanceTiming= Windows.performance.timing
返回值为一个对象, 记录着完整的页面加载信息. 其各个节点如下:
图片摘自网络
看着上图, 回顾一下一般意义的页面加载过程: 浏览器向服务器请求资源 --> 构建 DOM 树 --> 构建 CSS 规则树 --> 构建渲染树 --> 绘制页面. 当然这个过程不全, 也基本与上图有吻合之处, 今天就更深入的理解该过程.
Prompt for unload 阶段
.navigationStart: 浏览器完成卸载前一个文档的时间. 如果没前一个文档, 则该值与第三步. fetchStart 的值相同.
.unloadEventStart: 返回前一个同源文档发生 unload 事件前的时间. 如果没有前一个文档, 或前文档与本文档不同源, 或需重定向, 则返回 0.
.unloadEventEnd: 返回前一个同源文档结束 unload 事件的时间. 如果没有或不同源, 则返回 0.
Redirect 阶段
.redirectStart:http 重定向开始的时间. 如果中间有多个重定向, 且每个重定向均同源, 则返回第一个重定向的. fetchStart 时间, 若不同源, 则为 0
.redirectEnd:http 重定向结束时间. 如果中间有多个重定向且均同源, 则返回最后一个重定向结束时间. 若不同源, 则为 0.
App cache 阶段
.fetchStart: 浏览器准备好使用 HTTP 请求来获取 (fetch) 文档的时间, 这个时间会在检查任何应用缓存之前.
DNS 查询阶段
.domainLookupStart: 用户代理对当前文档所属域进行 DNS 查询开始的时间. 如果是长连接(如 websocket), 或本地缓存了, 则该值与. fetchStart 相同
.domainLookupEnd: 域名查询结束的时间. 如果是长连接, 或本地缓存了, 则该值与. fetchStart 相同
TCP 连接阶段
.connectStart: 用户代理开始向服务器请求所需文档时, 连接建立的开始时间. 如果是长连接, 或本地缓存了, 则该值与. fetchStart 相同
.secureConnectStart: 返回与服务器开始 SSL 握手时的时间. 异常情况同上.
.connectEnd: HTTP 握手成功, 认证结束, 连接建立时的时间. 如果是长连接, 或本地缓存了, 则该值与. fetchStart 相同.
Request 阶段
requestStart: 从服务器 / 缓存 / 本地资源中开始请求文档的时间. 如果连接发生断开重连, 该信息会被刷新.
没有请求结束时间是因为该动作发生在服务器端, 且受数据链路等各个因素影响, 浏览器并不能准确反馈该信息
Response 阶段
.responseStart: 从服务器 / 缓存 / 本地资源中接收到第一个字节时的时间. 如果连接发生断开重连, 该信息会被刷新.
.responseEnd: 从服务器 / 缓存 / 本地资源中接收到最后一个字节时的时间. 如果连接提前关闭, 则返回提前关闭的时间. 获取该值时需注意要在 Response 结束之后, 如 Windows.onload, 否则可能不准确.
Processing 执行阶段
.domLoading: 资源下载完成, 开始解析 DOM 结构, 当 Document.readyState 的值更新为 loading 时的时间.
.domInteractive:DOM 解析完成, 开始加载内嵌资源, 即 Document.readyState 的值更新为 interactive 时的时间
执行阶段内的 DOMContentLoaded 阶段
.domContentLoadedEventStart
: 解析器发送 DOMContentLoaded 事件, 所有需要被执行的脚本均解析完成时的时间.
.domContentLoadedEventEnd
: 所有立即执行的脚本均执行完成时的时间. 不执行的脚本如懒加载资源不在该范围内.
.domComplete: 当前文档解析完成, document.readyState 的值更新为 complete 时的时间.
load 业务涉入阶段
.loadEventStart: 文档触发 load 事件的时间, 如果还没触发, 则返回 0.
.loadEventEnd: 文档结束 load 事件的时间, 未触发则返回 0.
# 性能监控指标
通过以上的各个事件分析, 不难得出如下各个时间段:
const timing = Windows.performance.timing
DNS 解析耗时:
timing.domainLookupEnd - timing.domainLookupStart
TCP 连接耗时:
timing.connectEnd - timing.connectStart
发送请求耗时:
timing.responseStart - timing.requestStart
接收请求耗时:
timing.responseEnd - timing.responseStart
解析 DOM 耗时:
timing.domInteractive - timing.domLoading
页面加载完成:
timing.domContentLoadedEventStart - timing.domInteractive
DOMContentLoaded 事件耗时:
timing.domContentLoadedEventEnd - timing.domContentLoadedEventStart
DOM 加载完成:
timing.domComplete - timing.domContentLoadedEventEnd
DOMLoad 事件耗时:
timing.loadEventEnd - timing.loadEventStart
除此之外, 在文首提到的其他几个性能指标, 如下:
白屏时间:
timing.responseStart - timing.navigationStart
首屏时间:
timing.domComplete- timing.navigationStart
资源下载总耗时:
timing.responseEnd - timing.requestStart;
请求完毕至 DOM 加载:
- timing.domInteractive - timing.responseEnd
- # 结束语
参考文献
performance - MDN
HTML5 performance API 草案.
来源: http://www.jianshu.com/p/5d3b9ef2f599