VUE(nuxt)項目性能監測統計

最近有個需求是監測性能,要求在移動端項目裏統計控制檯(如下圖)最後一行的Finish,DOMContentLoaded和Load三個時間。
在這裏插入圖片描述

一、指標解釋

(1)Finish

  • Finish 時間是頁面上所有 http 請求發送到響應完成的時間,HTTP1.0/1.1 協議限定,單個域名的請求併發量是 6 個,即Finish是所有請求(不只是XHR請求,還包括DOC,img,js,css等資源的請求)在併發量爲6的限制下完成的時間。

  • 頁面發送請求和頁面解析文檔結構,分屬兩個不同的線程,所以 Finish 時間與DOMContentLoaded 和 Load 並無直接關係。

  • Finish 的時間比 Load 大,意味着頁面有相當部分的請求量,Finish 的時間比 Load 小,意味着頁面請求量很少,如果頁面是隻有一個 html文檔請求的靜態頁面,Finish時間基本就等於HTML文檔請求的時間。

(2)DOMContentLoaded

  • 對應頁面DOMContentLoaded事件觸發的時間點:DOM樹構建完成。即HTML頁面由上向下解析HTML結構到末尾封閉標籤 。

(3)Load

  • 對應頁面Load事件觸發的時間點:頁面加載完畢。 DOM樹構建完成後,繼續加載html/css 中的圖片資源等外部資源,加載完成後視爲頁面加載完畢。

二、http請求過程及網頁渲染原理

(1)http請求過程

在這裏插入圖片描述

(2)渲染原理

在這裏插入圖片描述
當我們在瀏覽器地址輸入URL時,瀏覽器會發送請求到服務器,服務器將請求的HTML文檔發送回瀏覽器,瀏覽器將文檔下載下來後,便開始從上到下解析,解析完成之後,會生成DOM。如果頁面中有css,會根據css的內容形成CSSOM,然後DOM和CSSOM會生成一個渲染樹,最後瀏覽器會根據渲染樹的內容計算出各個節點在頁面中的確切大小和位置,並將其繪製在瀏覽器上。

html的解析又會被js打斷,解析過程中遇到

而在現在瀏覽器中,爲了減緩渲染被阻塞的情況,現代的瀏覽器都使用了猜測預加載。當解析被阻塞的時候,瀏覽器會有一個輕量級的HTML(或CSS)掃描器(scanner)繼續在文檔中掃描,查找那些將來可能能夠用到的資源文件的url,在渲染器使用它們之前將其下載下來,並且下載是可以並行進行的,並行的上限一般爲6。

三、Performance API

具體參考js標準教程Performance API

主要用到的是performance.timing對象,具體解釋見上面的鏈接,下面這張圖對應各個指標的時間點。
在這裏插入圖片描述

參考這段代碼的統計指標

(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

原文連接

https://www.jianshu.com/p/2bbce858ef0f

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章