跳转至

探究007性能指标的实现方式

一、Performance 对象

007性能指标是利用了Performance对象,可以通过window.performance获取Performance

Performance可以获得性能数据(timing)、内存数据(memory)等。这里仅介绍performance.timing属性,其他 API 可参阅后面的链接。

下面按照触发顺序看一下各个属性的含义。

1. prompt for unload 上一个页面卸载

  • navigationStart:在同一个浏览器上下文中,前一个网页(与当前页面不一定同域)unload 的时间戳,如果无前一个网页 unload ,则与 fetchStart 值相等
  • unloadEventStart:前一个网页(与当前页面同域)unload的时间戳,如果无前一个网页 unload 或者前一个网页与当前页面不同域,则值为 0
  • unloadEventEnd:和 unloadEventStart 相对应,返回前一个网页 unload 事件绑定的回调函数执行完毕的时间戳

2. 重定向

  • redirectStart:第一个 HTTP 重定向发生时的时间。有跳转且是同域名内的重定向才算,否则值为 0
  • redirectEnd:最后一个 HTTP 重定向完成时的时间。有跳转且是同域名内的重定向才算,否则值为 0
  • fetchStart:浏览器准备好使用 HTTP 请求抓取文档的时间,这发生在检查本地缓存之前

3. DNS解析

  • domainLookupStart:DNS 域名查询开始的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等
  • domainLookupEnd:DNS 域名查询完成的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等

4. TCP三次握手

  • connectStart:HTTP(TCP) 开始建立连接的时间,如果是持久连接,则与 fetchStart 值相等,如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接开始的时间
  • connectEnd:HTTP(TCP) 完成建立连接的时间(完成握手),如果是持久连接,则与 fetchStart 值相等,如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接完成的时间
  • secureConnectionStart:HTTPS 连接开始的时间,如果不是安全连接,则值为 0

5. 请求数据

  • requestStart:HTTP 请求读取真实文档开始的时间(完成建立连接),包括从本地读取缓存,连接错误重连时,这里显示的也是新建立连接的时间
  • responseStart:HTTP 开始接收响应的时间(获取到第一个字节),包括从本地读取缓存
  • responseEnd:HTTP 响应全部接收完成的时间(获取到最后一个字节),包括从本地读取缓存

6. processing,JS执行、DOM解析渲染

  • domLoading:开始解析渲染 DOM 树的时间,此时 Document.readyState 变为 loading,并将抛出 readystatechange 相关事件
  • domInteractive:完成解析 DOM 树的时间,Document.readyState 变为 interactive,并将抛出 readystatechange 相关事件
  • domContentLoadedEventStart:DOM 解析完成后,网页内资源加载开始的时间,文档发生 DOMContentLoaded事件的时间
  • domContentLoadedEventEnd:DOM 解析完成后,网页内资源加载完成的时间(如 JS 脚本加载执行完毕),文档的DOMContentLoaded 事件的结束时间
  • domComplete:DOM 树解析完成,且资源也准备就绪的时间,Document.readyState 变为 complete,并将抛出 readystatechange 相关事件

7. load事件开始

  • loadEventStartload 事件发送给文档,也即 load 回调函数开始执行的时间,如果没有绑定 load 事件,值为 0
  • loadEventEndload 事件的回调函数执行完毕的时间,如果没有绑定 load 事件,值为 0

看完上面的属性,是不是有似曾相识的感觉,就是那个常见的问题"浏览器输入一个URL会依次发生什么",只不过performance精确获取了这些时间。

二、007性能指标

源码中可以看到007性能指标的计算方法。007的性能指标包括:

  1. DNS 连接耗时
  2. TCP连接耗时
  3. 后端响应时间
  4. HTML 页面下载时间
  5. DOM 时间
  6. 首次加载耗时
  7. 整页耗时
  8. 解析 DOM 树耗时

它们的计算方式如下:

timeOrigin = performance.wx.timeOrigin || performance.timing.fetchStart

1. DNS 连接耗时:domainLookupEnd - domainLookupStart;
2. TCP 连接耗时:connectEnd - connectStart;
3. 后端响应时间:responseStart - requestStart
4. HTML 页面下载时间: responseEnd - responseStart
5. DOM 时间:domContentLoadedEventStart - responseEnd
6. 首屏时间(首次加载耗时):domLoading - timeOrigin
7. 首页时间(整页耗时): loadEventEnd - timeOrigin
8. 解析 DOM 树耗时: domComplete - domInteractive

performance.timing即将被废弃,取而代之的是PerformanceNavigationTiming,绝大部分 API 是差不多的,只是后者换成了相对时间,前者是时间戳,即绝对时间。

可以试试下面的代码:

1
2
3
4
5
6
7
function showNavigationDetails() {
  // Get the first entry
  const [entry] = performance.getEntriesByType("navigation");
  // Show it in a nice table in the developer console
  console.table(entry.toJSON());
}
showNavigationDetails();

三、相关问题

1、对于Vue这样的单页应用,路由跳转后的页面加载会另外计算吗?

不会。路由跳转不会触发unload事件。另外,试验也发现,跳转后的页面打印的performancedomloingfetchStart的时间与上一页面相同。

所以对跳转后的页面做的优化并不会影响到首屏的时间,比如对二次页面的预加载等手段。

2、不同工具的首屏时间不一致?

这很常见。首屏时间的计算方式有多种,有的人用加载最慢的图片的时间点 - navigationStart,有的人用加载最慢的图片的时间点 - loadEventStart,还有的会区分SSR和SPA应用

首屏时间指的是浏览器显示第一屏页面所消耗的时间,包含了DNS解析、TCP握手、资源加载、DOM解析等时间,只要能囊括这些时间的指标都可以使用,毕竟使用中更多的是横向对比和纵向对比,而不是对比指标数据本身。

3、 如何减少首屏时间?

从首屏的概念和其包含的阶段可以看出,只要能减少其中包含步骤的时间,就能降低首屏时间。

常用方法包括: - 图片和JS的懒加载、按需加载 - 使用CDN资源 - 文件压缩和合并 - 使用http2 - 使用缓存

四、相关资料

  1. 007-Performance
  2. MDN-Performance
  3. W3C Editor's Draft
  4. Performance — 前端性能监控利器
  5. 性能优化篇 - Performance(工具 & api)
  6. JS:Performance
  7. 前端优化-如何计算白屏和首屏时间
  8. 前端首屏优化
  9. 前端性能指标{Performance}