前端效能監控

轉轉_陳龍發表於2019-04-03

從一道經典的面試題開始

(本文部分內容整理自網路文章)

使用者從輸入 URL 到頁面載入完成,都發生了什麼?

image

  1. DNS 解析 (解析域名,將URL解析為對應的IP地址)
  2. TCP 連線(與這個IP建立TCP網路連線,三次握手)
  3. 傳送HTTP 請求
  4. 服務端相應HTTP 返回資料
  5. 瀏覽器拿到響應資料,解析響應內容,把解析的結果展示給使用者

前端效能都包括哪些

image

這個效能劃分是我從一篇文章上扒下來的,我們這裡主要討論效能監控

前端效能監控-關鍵指標

  • 首屏時間
  • 白屏時間
  • 頁面總下載時間

瀏覽器效能先關內容概述

效能方面我們通過 window.preformance.timing 這個屬性來獲取效能相關引數

window.preformance.timing(記錄了頁面各個狀態的時間戳)

image

那麼這些引數都是什麼意義,以及它們觸發機制是什麼

我來看一張經典的圖

image

我們把它翻譯一下

【Prompt for unload】- 使用者跳轉行為(在位址列輸入url後按回車,或者點選a標籤跳轉等)
 navigationStart、startTime // 當前瀏覽器視窗的前一個網頁關閉開始執行的時間戳
 unloadStart // 前一個頁面unload觸發開始時間戳
【unload】- 前一個頁面unload時間
 unloadEnd // 前一個頁面unload觸發結束時間戳
 redirectStart // 返回第一個HTTP跳轉開始時的時間戳如果沒有跳轉,或者不是同一個域名內部的跳轉,則返回值為0
【redirect】- 重定向
 redirectEnd // 返回最後一個HTTP跳轉結束時(即跳轉回應的最後一個位元組接受完成時)的時間戳,如果沒有跳轉,或者不是同一個域名內部的跳轉,則返回值為0
 fetchStart // 返回瀏覽器準備使用HTTP請求讀取文件時的時間戳。該事件在網頁查詢本地快取之前發生
【App cache】- 網頁查詢本地快取
 domainLookupStart // 返回域名查詢開始時的時間戳。如果使用持久連線,或者資訊是從本地快取獲取的,則返回值等同於fetchStart屬性的值
【DNS】- 域名查詢
 domainLookupEnd // 返回域名查詢結束時的時間戳。如果使用持久連線,或者資訊是從本地快取獲取的,則返回值等同於fetchStart屬性的值
 connectStart // 返回建立TCP連結開始向伺服器傳送時的時間戳。如果使用持久連線(persistent connection),則返回值等同於fetchStart屬性的值
【TCP】
 secureConnectionStart // 它的值是安全連線握手之前的時刻。如果該屬性不可用,則返回undefined。如果該屬性可用,但沒有使用HTTPS,則返回0
 connectEnd // 返回瀏覽器與伺服器之間的連線建立時的時間戳。如果建立的是持久連線,則返回值等同於fetchStart屬性的值。連線建立指的是所有握手和認證過程全部結束
回瀏覽器與伺服器開始安全連結的握手時的時間戳。如果當前網頁不要求安全連線,則返回0
 requestStart // 返回瀏覽器向伺服器發出HTTP請求時(或開始讀取本地快取時)的時間戳
【Request】 - 網路請求
 responseStart // 返回瀏覽器從伺服器收到(或從本地快取讀取)第一個位元組時的時間戳
【Response】
 responseEnd // 返回瀏覽器從伺服器收到(或從本地快取讀取)最後一個位元組時(如果在此之前HTTP連線已經關閉,則返回關閉時)的時間戳
 domLoading // 返回當前網頁DOM結構開始解析時(即Document.readyState屬性變為“loading”、相應的readystatechange事件觸發時)的時間戳
【Processing】
 domInteractive // 返回當前網頁DOM結構結束解析、開始載入內嵌資源時(即Document.readyState屬性變為“interactive”、相應的readystatechange事件觸發時)的時間戳
 domContentLoadedEventStart // 返回當前網頁DOMContentLoaded事件發生時(即DOM結構解析完畢、所有指令碼開始執行時)的時間戳
 domContentLoadedEventEnd // 返回當前網頁所有需要執行的指令碼執行完成時的時間戳
 domComplete // 返回當前網頁DOM結構生成時(即Document.readyState屬性變為“complete”,以及相應的readystatechange事件發生時)的時間戳
 loadEventStart // 返回當前網頁load事件的回撥函式開始時的時間戳。如果該事件還沒有發生,返回0
【onLoad】- window.onLoad觸發
 loadEventEnd // 返回當前網頁load事件的回撥函式執行結束時的時間戳。如果該事件還沒有發生,返回0。通過while迴圈持續判斷直到loadEventEnd>0則表示完全載入完畢了!網路不再有任何資料請求、dom也渲染完畢了
複製程式碼

注意

由於window.preformance.timing是一個在不同階段,被不停修正的一個引數物件,所以,建議在window.onload中進行效能資料讀取和上報

關鍵資料獲取

  • 首屏時間:計算起來比較麻煩,後文會詳述
  • 白屏時間:responseEnd - navigationStart
  • 頁面總下載時間:loadEventEnd - navigationStart

其他資料:

  • DNS解析耗時:domainLookupEnd - domainLookupStart
  • TCP連結耗時:connectEnd - connectStart
  • 首包請求耗時:responseEnd - responseStart
  • dom解釋耗時:domComplete - domInteractive
  • 使用者可操作時間:domContentLoadedEventEnd - navigationStart
  • ...

首屏時間計算

目前業內對首屏時間方式並不統一,常見的有下面幾種計算方式:

  • 利用首屏中最後一張圖片載入完成的時間來當做首屏時間(適合首屏元素由服務端渲染

方法:給頁面所有的img繫結onload事件,用來記錄圖片載入時間;在window.onload中,計算每一個img的offsetTop;把符合首屏高度的圖片資料收集起來,計算最大onload時間

  • 圖片相似度比較法,通過比較連續截圖影像的畫素點變化趨勢確定首屏時間(適合非同步請求資料渲染的場景

方法:通過html2canvas外掛,每100ms擷取螢幕;然後獲取螢幕九宮格每一格中心點的,獲取紅色通道的畫素相加得到一個值,通過不斷截圖和比較這個求和的值,監控出首屏是否載入完畢。(截圖影像相似度比較的方法最為科學和直觀,但是比較消耗本地裝置的執行資源。而且由於比較複雜的運算,會影響到頁面邏輯指令碼執行的效能)

  • 首屏模組標籤標記法(頁面多數非同步請求渲染)

方法:在 HTML 文件中對應首屏內容的標籤結束位置,使用內聯的 JavaScript 程式碼記錄當前時間戳

  • 自定義模組內容計演算法(自定義每個頁面太複雜)

方法:通過自定義模組內容,來簡化計算首屏時間

  • 用onLoad或者domReady觸發時間表示首屏時間

我們的首屏計算方式

首先我們要介紹一下window.performance.getEntries()方法,因為後面會用到

window.performance.getEntries()

呼叫後會獲取頁面載入資源和網路請求資訊

image

拿到之後是個陣列,裡面包含了頁面所有的靜態資源、網路請求相關資訊,我們通過initiatorType來獲取每一個元素的屬性

image

“xmlhttprequest”表示的就是介面請求

首屏計算方式

  • 預設值為:domContentLoadedEventEnd - navigationStart
  • 如果是vue專案,採用mounted觸發時間作為計算分界點。
  • 如果是react專案,採用componentDidMount觸發時間作為計算分界點。
  • 遍歷window.performance.getEntries()所有內容,過濾mounted、componentDidMount之前發出的所有請求內容,如果有xmlhttprequest,則採用最後返回response的時間作為首屏時間
  • 如果是ssr專案,直接採用預設計算方式(domContentLoadedEventEnd - navigationStart)

可能大家會有疑問,我們首屏時間的計算中,不包含渲染和圖片載入時間?

確實,我們這麼做有兩個前提:

  • 通常情況下我們認為瀏覽器渲染時間會很快
  • 頁面載入的圖片必須進行擷取(這個由各業務線自己控制)

所以這種首屏計算方式,更像是“首屏資料開始渲染時間”(因為此時已經拿到了首屏渲染所有需要的資料)

在圖片過多、過大時候是會有一定程度的誤差

我們為什麼這麼做?

  • 為了實現自動統計,且不希望效能統計的邏輯被強制注入到的業務程式碼中
  • 儘可能的接近真實的首屏載入時間
  • 在不過多佔用瀏覽器首屏載入效能的情況下完成資料收集

首屏時間目前各家公司的計算方式不盡相同,但是所採用的,一定是在符合各自公司真實情況的前提下,最接近於首屏時間的計算方式。

其實資料準確性和收集資料的效能開銷,是一種博弈,對於公司來講,應該選擇最合適的方式。

相關文章