β

浏览器请求性能数据

小曹哥的博客 86 阅读

性能似乎是编程当中一个永恒的话题,前端也不例外,而前端考虑性能的重要目的是提升用户体验。前端性能可以粗略地分为两部分:传输性能与运行性能。 传输性能 主要就是加载资源的请求耗时, 运行性能 主要就是应用运行时 CPU 耗时、内存及 GPU 内存等。通常在开发阶段,经常使用浏览器开发者工具来查看请求性能,比如查看 DOMContentLoaded load 事件时间,又比如查看某个 AJAX 请求的相关时间。而由于线上产品会被不同地区不同网络条件的用户访问,可能全中国,也可能全球,可能使用电信,也可能使用网通,可能使用光纤,也可能是 4G。因此,要准确地衡量不同用户的请求耗时,就不能简简单单地通过自己的浏览器查看页面。有一种方式是通过遍布全国机房的服务端程序来发起请求统计不同地区请求耗时,但机房网络条件通常都比用户的网络条件好,所以这种方法还是不准确。

相关规范

因此, W3C Web 性能工作组(W3C Web Performance Working Group) 制定了用户测量请求性能的规范:

相关规范及发布状态请查看 表格

High-Resolution Time

该规范主要定义了 DOMHighResTimeStamp 类型,用于存放精读最高可达 5 微秒的时间值,单位是毫秒。至于,为什么精读只能到 5 微妙,是因为 隐私与安全考虑

另外该规范还定义了 Performance 接口以及该接口的实现 performance 全局属性,一些性能相关的接口都挂载这个属性上面。

Resource Timing

该规范定义了 PerformanceResourceTiming 接口,这个接口用于页面内资源请求的时间测量。

PerformanceResourceTiming 接口

该接口扩展了 PerformanceEntry 接口属性。例如下图展示了 Chrome 58 所支持的属性:

PerformanceResourceTiming 接口属性

各属性的含义还是比较直观的,下图展示一个请求周期各阶段的划分:

Resource Timing 请求阶段划分

具体各属性的含义及属性值详见规范中的 解释

哪些资源包含在 PerformanceResourceTiming 接口里面

此接口包括的请求类型有:XMLHttpRequest 对象,HTML 元素 iframe、image、script、object、embed、link[type=”stylesheet”]、svg。而 Server Sent Events 和 WebSocket 并不包括,可能是因为这些连接属于“长连接”,而 Fetch API 发起的请求,旧版本浏览器是不支持的。

具体哪些资源加载应该包含进 PerformanceResourceTiming ,既要看 规范规定 ,也要实际测量,各浏览器及各版本支持情况可能不同。

Navigation Timing

规范定义了 PerformanceNavigationTiming 接口,该接口扩展了 PerformanceEntry PerformanceResourceTiming 接口,下图展示了 Chrome 58 所支持的属性:

PerformanceNavigationTiming 接口属性

各属性的含义还是比较直观的,下图展示一个请求周期各阶段的划分:

Navigation Timing 请求阶段划分

Performance Timeline

Performance Timeline 规范定义了获取页面请求性能即页面资源请求性能信息的接口。

通常使用下面代码获取页面资源请求性能:

performance.timing;
// 或
performance.getEntriesByType('navigation'); // 需浏览器支持 performance.getEntriesByType() 方法,不如 performance.timing 兼容性好

兼容性

Can I use 网站包含上面规范的兼容性,但是不详细,没有说明规范的各版本支持情况,也不包括 Performance Timeline 兼容性信息。

收集请求性能信息

获取请求性能信息

通过 performance.timing 即可获取当前页面请求性能信息。下面主要说下获取页面资源请求的性能信息注意事项:

Resource Timing 包含哪些资源

理论上所有从服务器请求的资源都被包含进来,但是有一些特殊情况,如 WebSockets、ServerSentEvent、DNS 查询失败、TCP 失败、服务端 4xx/5xx 响应等是否包含。

缓存的资源

目前没有办法区分资源是否从缓存中加载的,只不过缓存的资源,一般 duration 值非常小(比如小于 10 毫秒)。

ResourceTiming Buffer

每个页面文档都有一个 ResourceTiming buffer 用于限制可以包含多少 PerformanceResourceTiming 对象,默认情况下浏览器将此设为 150,这是规范当中建议设置的大小。而实际应用当中虽然页面初次加载请求数一般不会超过 150,但是后面的 AJAX 请求,或者说应用是单页面应用,则通常会超过 150。

可以使用一个方法监听 resourcetimingbufferfull 事件,然后当该事件触发时,使用 clearResourceTimings() 来清空已有的数据。如下代码所示:

// Send navigation timing data to server
function sendData() {
  const data = new Blob([JSON.stringify(performance.timing)], {
    type: 'application/json',
  });
  navigator.sendBeacon('/timing', data);
}
window.addEventListener('unload', sendData);

兼容性 : 可以参考 Beacon API in caniuse.com ,除了 IE 与 Safari,其他浏览器都在很早就支持了。

跨域 :可以查看规范的 Privacy and Security 部分,但是我在实际测试跨域发送 JSON 数据时,Chrome 58 当中不会发送额外的 OPTIONS 请求,而 Firefox 53 发送额外的 OPTIONS 请求,请求相应头部需要包含下面的跨域相关头部。

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Credentials: true

另外,使用 sendBeacon() 无法获知请求响应状态,不过这对于数据收集类请求不算问题。

相关链接

更新日志

性能似乎是编程当中一个永恒的话题,前端也不例外,而前端考虑性能的重要目的是提升用户体验。前端性能可以粗略地分为两部分:传输性能与运行性能。 传输性能 主要就是加载资源的请求耗时, 运行性能 主要就是应用运行时 CP

作者:小曹哥的博客
原文地址:浏览器请求性能数据, 感谢原作者分享。

发表评论