VUE(nuxt)项目性能监测统计

2018-11-03  本文已影响0人  我才是大田田

最近有个需求是监测性能,要求在移动端项目里统计控制台(如下图)最后一行的Finish,DOMContentLoaded和Load三个时间。

控制台截图

一、指标解释

(1)Finish

(2)DOMContentLoaded

(3)Load

二、http请求过程及网页渲染原理

(1)http请求过程

image

(2)渲染原理

image

当我们在浏览器地址输入URL时,浏览器会发送请求到服务器,服务器将请求的HTML文档发送回浏览器,浏览器将文档下载下来后,便开始从上到下解析,解析完成之后,会生成DOM。如果页面中有css,会根据css的内容形成CSSOM,然后DOM和CSSOM会生成一个渲染树,最后浏览器会根据渲染树的内容计算出各个节点在页面中的确切大小和位置,并将其绘制在浏览器上。

html的解析又会被js打断,解析过程中遇到<script>标签的时候,便会停止解析过程,转而去处理脚本,如果脚本是内联的,浏览器会先去执行这段内联的脚本,如果是外链的,那么先会去加载脚本,然后执行。在处理完脚本之后,浏览器便继续解析HTML文档。(所以一般js文件放到最后面)

而在现在浏览器中,为了减缓渲染被阻塞的情况,现代的浏览器都使用了猜测预加载。当解析被阻塞的时候,浏览器会有一个轻量级的HTML(或CSS)扫描器(scanner)继续在文档中扫描,查找那些将来可能能够用到的资源文件的url,在渲染器使用它们之前将其下载下来,并且下载是可以并行进行的,并行的上限一般为6。

三、Performance API

具体参考js标准教程Performance API

主要用到的是performance.timing对象,具体解释见上面的链接,下面这张图对应各个指标的时间点。


PerformanceNavigationTiming 过程

参考这段代码的统计指标

(function  performanceStatistics(){

  var performance = window.performance;

  if (!performance) {
      // 当前浏览器不支持
      console.log('你的浏览器不支持 performance 接口');
      return ;
  }
  var timing = performance.timing;
  // 如果我们需要尽量对页面加载周期的数据进行详细的统计分析:
  console.log('统计模块性能时间:'); // 写出具体模块名称
  console.log('准备新页面时间耗时: ' + (timing.fetchStart - timing.navigationStart) + 'ms');
  console.log('Appcache 耗时: ' + (timing.domainLookupStart - timing.fetchStart)+ 'ms');
  console.log('DNS 查询耗时: ' + (timing.domainLookupEnd - timing.domainLookupStart)+ 'ms');
  console.log('TCP连接耗时: ' + (timing.connectEnd - timing.connectStart)+ 'ms');
  console.log('request请求耗时: ' + (timing.responseEnd - timing.requestStart)+ 'ms');
  console.log('请求完毕至DOM加载: ' + (timing.domInteractive - timing.responseEnd)+ 'ms');
  console.log('解释dom树耗时: ' + ( timing.domComplete - timing.domInteractive)+ 'ms');
  console.log('load事件耗时: ' + ( timing.loadEventEnd - timing.loadEventStart)+ 'ms');
  console.log('从开始至load完成: ' + ( timing.loadEventEnd - timing.navigationStart)+ 'ms');
  console.log('页面加载耗时: ' + ( timing.loadEventStart - timing.navigationStart)+ 'ms');
  // 至此,我们可以将页面加载过程中的相关耗时详尽的统计输出,分析耗时较长的地方并作出相关的优化。
})()

因为是持久链接,所以domainLookupStart、domainLookupEnd、connectEnd都等于fetchStart,所以Appcache 耗时、DNS 查询耗时、TCP连接耗时都是0。

最后整出来3个指标:第一个对应控制台的DOMContentLoaded,第三个对应控制台的Load

DOM加载时间(timing.domContentLoadedEventStart - timing.navigationStart)
请求时间(timing.responseEnd - timing.requestStart)
页面加载时间(timing.loadEventStart - timing.navigationStart)

统计代码如下:

function performance(){
    var performance = window.performance;
    if (!performance) {return ;} 
    var path = window.location.pathname.replace(/(\d+)/g, '') , 
    timing = performance.timing, 
    DOMLoaded = timing.domContentLoadedEventStart - timing.navigationStart , 
    requestTime = timing.responseEnd - timing.requestStart , 
    pageLoaded = timing.loadEventStart - timing.navigationStart ; 
    _czc.push(['_trackEvent', 'DOMLoaded-time', 'show', path , DOMLoaded, '']) ;
    _czc.push(['_trackEvent', 'requestTime-time', 'show',path, requestTime, '']) ; 
    _czc.push(['_trackEvent', 'pageLoaded-time', 'show', path, pageLoaded, '']) ;
}

四、监测代码加在哪儿

这个是个坑,因为项目采用的是nuxt(vue)的,单页面,但是每个页面都需要统计这些数据,想写在全局。试了好多方案,最后选了一种。

方案1:在mounted里写
刚开始在首页试的,发现要写在window.onload里才能统计到真实数据。因为是单页面,就算在每个页面里写onload,取到的也都是一样的数。

方案2:中间件
这个可以写在全局,但是路由跳转的时候取不到window,设置延时或window.onload也不行。

方案3:插件
写了个js文件,nuxt.config.js配置了ssr: false,设置延时或window.onload还是不行。

方案4:nuxt.config.js加在script标签里。这个方案是可行的,能检测到第一次进入页面时的数据或者是刷新当前页面的数据。

{ innerHTML: "window.onload = function(){var performance = window.performance;if (!performance) {return ;} var path = window.location.pathname.replace(/(\d+)/g, '') , timing = performance.timing, DOMLoaded = timing.domContentLoadedEventStart - timing.navigationStart , requestTime = timing.responseEnd - timing.requestStart , pageLoaded = timing.loadEventStart - timing.navigationStart ; _czc.push(['_trackEvent', 'DOMLoaded-time', 'show', path , DOMLoaded, '']) ; _czc.push(['_trackEvent', 'requestTime-time', 'show',path, requestTime, '']) ; _czc.push(['_trackEvent', 'pageLoaded-time', 'show', path, pageLoaded, '']);}"}

即:

window.onload = function(){
    var performance = window.performance;
    if (!performance) {return ;} 
    var path = window.location.pathname.replace(/(\\d+)/g, '') , 
    timing = performance.timing, 
    DOMLoaded = timing.domContentLoadedEventStart - timing.navigationStart , 
    requestTime = timing.responseEnd - timing.requestStart , 
    pageLoaded = timing.loadEventStart - timing.navigationStart ; 
    _czc.push(['_trackEvent', 'DOMLoaded-time', 'show', path , DOMLoaded, '']) ;
    _czc.push(['_trackEvent', 'requestTime-time', 'show',path, requestTime, '']) ; 
    _czc.push(['_trackEvent', 'pageLoaded-time', 'show', path, pageLoaded, '']) ;
}

遇到的问题:
1、var path = window.location.pathname.replace(/(\d+)/g, '') 这段代码在浏览器控制台能起效,但是统计数据里还是会带着后面的参数id。
发现是转义了匹配上了字母d。。。要加个转义符\

2、统计数据并不全,不是所有的页面都能统计全3个指标,猜想是因为跳转影响了友盟统计。

这个戳单页面数据采集
如果需要准确的数据,可能需要重写 history.replaceState 在方法,在里面加上自定义的统计。

参考

https://segmentfault.com/q/1010000011840948/a-1020000011947156
https://www.cnblogs.com/caizhenbo/p/6679478.html
https://blog.csdn.net/TMQ1225/article/details/80454066
https://www.kancloud.cn/kancloud/javascript-standards-reference/46507#performancegetEntries_137

上一篇下一篇

猜你喜欢

热点阅读