本文首發於知乎 《10分鐘完全搞懂前端頁面性能監控》,搬運轉載請註明出處,不然追究版權責任。
前端頁面性能是一個很是核心的用戶體驗指標。本文介紹阿里UC 嶽鷹全景監控平臺 如何設計一個通用、低侵入性、自動上報的頁面性能監控方案。主要採用的是Navigation Timing API以及sendBeacon等方法。前端
一個頁面性能差的話會大大影響用戶體驗。用戶打開頁面等待的過久,可能會直接關掉頁面,甚至就再也不使用了,這種狀況在移動端更加明顯,移動端用戶對頁面響應延遲容忍度很低。vue
雖然頁面性能很重要,可是在實際使用中,頁面性能差的狀況並很多見。首先,在產品的迭代演進過程當中,頁面性能可能會被忽略,性能隨着版本迭代而有所衰減;其次,性能優化是一項複雜而挑戰的事情,須要明確的優化方向和具體的優化手段才能快速落地取效。react
因此咱們須要一個性能監控系統,持續監控和預警頁面性能的情況,而且在發現瓶頸的時候指導優化工做。web
爲了幫助開發者更好地衡量和改進前端頁面性能,W3C性能小組引入了 Navigation Timing API ,實現了自動、精準的頁面性能打點;開發者能夠經過 window.performance
屬性獲取。後端
performance.timing
接口(定義了從 navigationStart
至 loadEventEnd
的 21 個只讀屬性)performance.navigation
(定義了當前文檔的導航信息,好比是重載仍是向前向後等)下圖是W3C初版的 Navigation Timing 的處理模型。從當前瀏覽器窗口卸載舊頁面開始,到新頁面加載完成,整個過程一共被切分爲 9 個小塊:提示卸載舊文檔、重定向/卸載、應用緩存、DNS 解析、TCP 握手、HTTP 請求處理、HTTP 響應處理、DOM 處理、文檔裝載完成。每一個小塊的首尾、中間作事件分界,取 Unix 時間戳,兩兩事件之間計算時間差,從而獲取中間過程的耗時(精確到毫秒級別)。api
上圖是 Level 1 的規範,2012 年末進入候選建議階段,至今仍在平常使用中;可是在W3C的議程上,它已經功成身退,讓位給了精度更高,功能更強大,層次更分明的 Level 2(處理模型以下圖)。好比獨立劃分出來的 Resource Timing,使得咱們能夠獲取具體資源的詳細耗時信息。跨域
使用上面的指標,咱們能夠計算許多重要的指標,如首字節的時間,頁面加載時間,dns查找以及鏈接是否安全。咱們把 Navigation Timing API 提供的指標作下歸類,按照從上到下的時間流,右邊的時刻標記了每一個指標從哪裏開始計算到哪裏截止,好比,跳轉時間 redirect 由 redirectEnd - redirectStart
計算獲得,其餘的類推。瀏覽器
頁面性能統計的起始點時間,應該是用戶輸入網址回車後開始等待的時間。一個是經過navigationStart
獲取,至關於在URL輸入欄回車或者頁面按F5刷新的時間點;另一個是經過 fetchStart
,至關於瀏覽器準備好使用 HTTP 請求獲取文檔的時間。緩存
從開發者實際分析使用的場景,瀏覽器重定向、卸載頁面的耗時對頁面加載分析並沒有太大做用;一般建議使用 fetchStart
做爲統計起始點。安全
主文檔返回第一個字節的時間,是頁面加載性能比較重要的指標。對用戶來講通常無感知,對於開發者來講,則表明訪問網絡後端的總體響應耗時。
用戶看到頁面展現出現一個元素的時間。不少人認爲白屏時間是頁面返回的首字節時間,但這樣其實並不精確,由於頭部資源還沒加載完畢,頁面也是白屏。
相對來講具有「白屏時間」統計意義的指標,能夠取 domLoading - fetchStart
,此時頁面開始解析DOM樹,頁面渲染的第一個元素也會很快出現。
從W3C Navigation Timing Level 2 的方案設計,能夠直接採用 domInteractive - fetchStart
,此時頁面資源加載完成,即將進入渲染環節。
首屏時間是指頁面第一屏全部資源完整展現的時間。這是一個對用戶來講很是直接的體驗指標,可是對於前端倒是一個很是難以統計衡量的指標。
具有必定意義上的指標可使用,domContentLoadedEventEnd - fetchStart
,甚至使用loadEventStart - fetchStart
,此時頁面DOM樹已經解析完成而且顯示內容。
如下給出統計頁面性能指標的方法。
let times = {}; let t = window.performance.timing; // 優先使用 navigation v2 https://www.w3.org/TR/navigation-timing-2/ if (typeof win.PerformanceNavigationTiming === 'function') { try { var nt2Timing = performance.getEntriesByType('navigation')[0] if (nt2Timing) { t = nt2Timing } } catch (err) { } } //重定向時間 times.redirectTime = t.redirectEnd - t.redirectStart; //dns查詢耗時 times.dnsTime = t.domainLookupEnd - t.domainLookupStart; //TTFB 讀取頁面第一個字節的時間 times.ttfbTime = t.responseStart - t.navigationStart; //DNS 緩存時間 times.appcacheTime = t.domainLookupStart - t.fetchStart; //卸載頁面的時間 times.unloadTime = t.unloadEventEnd - t.unloadEventStart; //tcp鏈接耗時 times.tcpTime = t.connectEnd - t.connectStart; //request請求耗時 times.reqTime = t.responseEnd - t.responseStart; //解析dom樹耗時 times.analysisTime = t.domComplete - t.domInteractive; //白屏時間 times.blankTime = (t.domInteractive || t.domLoading) - t.fetchStart; //domReadyTime times.domReadyTime = t.domContentLoadedEventEnd - t.fetchStart;
Navigation Timing API能夠監控大部分前端頁面的性能。但隨着SPA模式的盛行,相似vue,reactjs等框架的普及,頁面內容渲染的時機被改變了,W3C標準沒法徹底知足原來的監控意義。
幸運的是,目前W3C關於首屏統計已經進入了提議階段,以Chrome爲首的瀏覽器正在打造更能表明用戶使用體驗的FP、FCP、FMP指標,而且逐步開放API。
測量好時間後,就須要將數據發送給服務端。頁面性能統計數據對丟失率要求比較低,且性能統計應該在儘可能不影響主流程的邏輯和頁面性能的前提下進行。
var i = new Image(); i.onload = i.onerror = i.onabort = function () { i = i.onload = i.onerror = i.onabort = null; } i.src = url;
大部分現代瀏覽器都支持 navigator.sendBeacon方法。這個方法能夠用來發送一些統計和診斷的小量數據,特別適合上報統計的場景。
window.addEventListener('unload', logData, false); function logData() { navigator.sendBeacon("/log", analyticsData); }
當瀏覽器支持sendBeacon方法,優先使用該方法,使用img方式降級上報。
navigation-timing-2 https://www.w3.org/TR/navigation-timing-2/
Navigation API指南 https://s0developer0mozilla0org.icopy.site/en-US/docs/Web/Performance/Navigation_and_resource_timings
以用戶爲中心的性能指標 https://developers.google.com/web/fundamentals/performance/user-centric-performance-metrics?hl=zh-cn
頁面性能對業務指標的影響 https://www.thinkwithgoogle.com/marketing-resources/data-measurement/mobile-page-speed-new-industry-benchmarks/