近年移動業務噴井式爆發,伴隨着互聯網人口紅利的萎縮,用戶更加青睞效率高體驗優的站點,頁面「到達」快慢直接影響了用戶的體驗,「性能」變得愈來愈重要。google 大數據統計觀察發現,移動端用戶對頁面加載慢的容忍度遠低於 PC 端,投放頁面首屏加載時間從 2s 鍾延遲到 3s 會形成 9.4% 的 PV 降低,8.3% 的跳出率增長以及 3.5% 的轉化率降低。性能優化具備的商業價值不言而喻,總不能眼看着市場同事辛苦「求」來的用戶在咱們手中流失吧?這是身爲一個合格前 yíng 臺 bīn 不能容許的!盤他!html
有些公司同時想到的第一件事就是「優化」,網上搜一波性能優化的列表,把別人的「最佳實踐」照搞一番,性能確實會有提高,但效率未必是最高的,反倒有些本末倒置,別人的問題未必就是本身的問題,「並行不表明因果」,要作性能優化,首先要作的是掌握詳盡的性能指標信息,根據木桶原理,找到最拖後腿的指標「短板」,重點優化,將邊際成本最小化。因此,首先咱們要作的應該是性能指標的收集分析。前端
指標收集主要分有三種方式:git
以 Google 的 Lighthouse 最爲著名,它是一個開源的自動化工具,能夠安裝爲 Chrome 的擴展插件,也能夠命令行直接運行,它將針對目標頁面運行一連串的測試,而後輸出一個有關頁面性能的評分報告。github
根據此報告,能夠有的放矢,逐一優化。web
優勢:算法
1. 評分報告全面且具備必定的權威性
2. 提供解決方案
3. 發現大的性能問題
複製代碼
缺點:api
1.存在「波動」,不一樣時刻的訪客羣體存在差別,數據只能反應當前時刻的「效果」
2.測試環境較單一,用戶羣體的環境各有不一樣,不能夠一律之
複製代碼
將目標頁面連接「委託」給第三方的服務,執行真實的訪問指令,同時收集性能指標生成報表輸出。數組
這種模式是在技術變現的背景下產生的,優秀的工具都是要付費的,固然開源和免費的優秀工具也不少,此前的阿里測就是其中一種,現已下線。停運的原因咱們很差揣測,此處謹向那些開源和提供免費服務的項目致敬!此處就再也不多推薦了,以避免有軟文的嫌疑。瀏覽器
在目標頁面注入腳本,在約定的時機收集性能指標數據,統一上報數據中心,數據中心集中整合生成報表,再根據報表分析性能。緩存
優勢:
1. 數據全面,可採集到全部用戶各個環境下的性能,生成直觀的分佈圖
2. 數據真實,來源於真實用戶
3. 反饋及時,優化後效果可及時地在報表上反饋出來
複製代碼
缺點:
依賴較多,數據中心和腳本都須要自主開發,相對成本較高
複製代碼
所謂監控,實際上就是性能「真實跟蹤」,雖然依賴較多,但對性能指標的反饋最爲真實有效。如下咱們將圍繞性能監控進行展開。
頁面的加載有多快?加載時間爲 X.XX 秒?
其實,好與壞,快與慢,都是很模糊的概念。咱們經常聽到別人介紹,「咱們的頁面白屏已經從 3s 優化到了 2s」,這種陳述的問題並非不真實,而是在於扭曲了事實。 加載白屏時間會因用戶不一樣而有很大的差別,具體取決於用戶的設備性能以及網絡情況。 咱們不能單純地以單個數字的形式呈現白屏時間而忽略加載時間過長的用戶。更況且,收集來的數據具備倖存者誤差性。
下圖是某頁面統計來的在必定時間段內用戶白屏時間分佈直方圖。能夠直觀反應出此頁面的「性能」狀況。
咱們能夠說,「90% 的用戶能夠在 3s 內完成頁面加載」,但「均值」或「中位數」僅能反應此頁面的某一點的表現,由於任何一個時間段都不能表明所有。
而性能優化的目標能夠是增長 1s 內的用戶比重,也能夠是將後面的用戶儘量的集中在 1s-2s 之間。這些都是須要根據產品特色和目標靈活調整的。
咱們所須要收集且重點關注的指標,應該是能準確反應用戶體驗的指標。
體驗 | 表現 | 指標 |
---|---|---|
是否發生? | 導航是否成功啓動?服務器是否有響應? | 首次繪製(FP)/首次內容繪製(FCP) |
是否有用? | 是否已渲染能夠與用戶互動的足夠內容? | 首次有效繪製(FMP)/主角元素計時 |
是否可用? | 用戶能夠與頁面交互,仍是頁面仍在忙於加載? | 可交互時間(TTI) |
是否使人愉快? | 交互是否順暢而天然,沒有滯後或卡頓? | 耗時較長的任務(在技術上不存在耗時較長的任務) |
如下時序屏幕截圖直觀地展現了用戶體驗點對應的指標,有助你們理解。
其中指標 FP 和 FCP 能夠經過瀏覽器點 API 計算獲取,而指標 FMP 和 TTI 因爲並無標準化的定義,所以也很難有標準化點 API 輸出, 部分緣由在於很難以通用的方式界定「有效」點。
除此關鍵指標以外,咱們同時也須要關注基礎指標,以便分析出形成關鍵指標「數據難看」的影響點。如 DNS 解析耗時、TCP 鏈接耗時、網絡請求耗時以及資源加載耗時等。
標準化定義的指標有如下幾種
Performance.timing 是一個只讀屬性,返回 PerformanceTiming 對象,該對象包括了頁面相關的性能信息。
startTime(navigationStart):在同一個瀏覽器上下文中,前一個網頁(與當前頁面不必定同域)unload 的時間戳,若是無前一個網頁 unload ,則與 fetchStart 值相等
unloadEventStart:前一個網頁(與當前頁面同域)unload 的時間戳,若是無前一個網頁 unload 或者前一個網頁與當前頁面不一樣域,則值爲 0
unloadEventEnd:和 unloadEventStart 相對應,返回前一個網頁 unload 事件綁定的回調函數執行完畢的時間戳
redirectStart:第一個 HTTP 重定向發生時的時間。有跳轉且是同域名內的重定向纔算,不然值爲 0
redirectEnd:最後一個 HTTP 重定向完成時的時間。有跳轉且是同域名內的重定向纔算,不然值爲 0
fetchStart:瀏覽器準備好使用 HTTP 請求抓取文檔的時間,這發生在檢查本地緩存以前
domainLookupStart:DNS 域名查詢開始的時間,若是使用了本地緩存(即無 DNS 查詢)或持久鏈接,則與 fetchStart 值相等
domainLookupEnd:DNS 域名查詢完成的時間,若是使用了本地緩存(即無 DNS 查詢)或持久鏈接,則與 fetchStart 值相等
connectStart:HTTP(TCP) 開始創建鏈接的時間,若是是持久鏈接,則與 fetchStart 值相等,若是在傳輸層發生了錯誤且從新創建鏈接,則這裏顯示的是新創建的鏈接開始的時間
connectEnd:HTTP(TCP) 完成創建鏈接的時間(完成握手),若是是持久鏈接,則與 fetchStart 值相等,若是在傳輸層發生了錯誤且從新創建鏈接,則這裏顯示的是新創建的鏈接完成的時間
注意:這裏握手結束,包括安全鏈接創建完成、SOCKS 受權經過
複製代碼
secureConnectionStart:HTTPS 鏈接開始的時間,若是不是安全鏈接,則值爲 0
requestStart:HTTP 請求讀取真實文檔開始的時間(完成創建鏈接),包括從本地讀取緩存,鏈接錯誤重連時,這裏顯示的也是新創建鏈接的時間
responseStart:HTTP 開始接收響應的時間(獲取到第一個字節),包括從本地讀取緩存
responseEnd:HTTP 響應所有接收完成的時間(獲取到最後一個字節),包括從本地讀取緩存
domLoading:開始解析渲染 DOM 樹的時間,此時 Document.readyState 變爲 loading,並將拋出 readystatechange 相關事件
domInteractive:完成解析 DOM 樹的時間,Document.readyState 變爲 interactive,並將拋出 readystatechange 相關事件
注意:只是 DOM 樹解析完成,這時候並無開始加載網頁內的資源
複製代碼
domContentLoadedEventStart:DOM 解析完成後,網頁內資源加載開始的時間,文檔發生 DOMContentLoaded事件的時間
domContentLoadedEventEnd:DOM 解析完成後,網頁內資源加載完成的時間(如 JS 腳本加載執行完畢),文檔的DOMContentLoaded 事件的結束時間
domComplete:DOM 樹解析完成,且資源也準備就緒的時間,Document.readyState 變爲 complete,並將拋出 readystatechange 相關事件
loadEventStart:load 事件發送給文檔,也即 load 回調函數開始執行的時間,若是沒有綁定 load 事件,值爲 0
loadEventEnd:load 事件的回調函數執行完畢的時間,若是沒有綁定 load 事件,值爲 0
更多解釋參見 W3C Recommendation - NavigationTiming 或 W3C Editor's Draft。
利用以上 API,咱們能夠計算出細顆粒度的性能基礎指標
基礎指標 | 描述 | 計算方式 | 備註 |
---|---|---|---|
rs | 準備新頁面耗時 | fetchStart - navigationStart | |
rdc | 重定向時間 | redirectEnd - redirectStart | |
dns | DNS 解析耗時 | domainLookupEnd - domainLookupStart | |
tcp | TCP 鏈接耗時 | connectEnd - connectStart | |
ssl | SSL 安全鏈接耗時 | connectEnd - secureConnectionStart | 只在 HTTPS 下有效 |
ttfb | Time to First Byte(TTFB),網絡請求耗時 | responseStart - requestStart | TTFB 有多種計算方式,ARMS 以 Google Development 定義爲準 |
trans | 數據傳輸耗時 | responseEnd - responseStart | |
dom | DOM 解析耗時 | domInteractive - responseEnd | |
res | 資源加載耗時 | loadEventStart - domContentLoadedEventEnd | 表示頁面中的同步加載資源 |
fbt | 首包時間 | responseStart - domainLookupStart | |
fpt | First Paint Time, 首次渲染時間 / 白屏時間 | responseEnd - fetchStart | 從請求開始到瀏覽器開始解析第一批 HTML 文檔字節的時間差 |
tti | Time to Interact,首次可交互時間(非準確,僅作參考) | domInteractive - fetchStart | 瀏覽器完成全部 HTML 解析而且完成 DOM 構建,此時瀏覽器開始加載資源 |
load | 頁面徹底加載時間 | loadEventStart - fetchStart | load = 首次渲染時間 + DOM 解析耗時 + 同步 JS 執行 + 資源加載耗時 |
關於兼容性,可參考下圖,絕大多數的瀏覽器已支持此 API,基本能夠放心地使用在移動端
相對於以上基礎指標,跟用戶感覺關聯最密切的可能就是各個「繪製(Paint)」時刻了,FP(First Paint),FCP(First Contentful Paint)以及 FMP(First Meaningful Paint)。
隨着 SPA(單頁面系統)的普及,單純靠 PerformanceTiming 要準確地計算出各 Paint 的時間是很難的。慶幸是的,Chrome 60+ 帶給咱們一個全新的 API,Paint Timing,它提供了抓取「頁面」和「資源」耗時的能力。此 API 尚處在實驗階段,並無歸入 W3C 的標準,因此,也僅僅是 webkit 內核的高版本瀏覽器才支持。聊勝於無。
Performance.getEntries() 方法以數組形式對網頁中每個對象(腳本文件、樣式表、圖片文件等等)發出的請求進行統計記錄,Paint 的就是其中的一種。咱們可使用方法 performance.getEntriesByType('paint')
輕鬆得到兩個 PerformancePaintTiming 對象,對應的分別就是 FP 和 FCP。
更多關於 FP 和 FCP,能夠參考此文 www.w3cplus.com/performance…
但關於 FMP,雖然 Chrome 的 Performance 工具已指示性地標出 FMP 的時間點,但依然未提供 API,部分原因可能就是「沒法標準化」吧。
因爲 Performance 的賦能,咱們沒有必要在頁面「最開始」就加載執行咱們的監控腳本,再小的文件也會阻塞首屏的繪製,可是,若是有依賴關係,如一些算法依賴於監控 DOM 的變化,仍是須要儘早進行初始化,因此時機應在 load 的先後,根據算法的須要進行調整,並無一個準確的方案。
數據收集到以後即是數據上報、處理
關於數據上報的成熟方案已有不少,「主動提交」,「反向代理」均可以,只要數據在不影響業務功能和性能的前提下完整地將上報到數據中心便可。
有了數據,咱們就能夠有目的性的將數據處理成咱們須要的形式。
能夠分析用戶分佈
橫向比較,細查差別因果,總結經驗。
也能夠按時間緯度展開,嗅探時間或流量對性能的影響,也能夠找到異常點,篩選出異常日誌重點關注。
總之,能夠將有限的數據玩出無限的可能!
以上,即是對性能監控的一些基礎介紹,但願對你有所幫助。
[1] 以用戶爲中心的性能指標
轉載請標明出處
做者: 木羽 zwwill
首發地址:zwwill/blog#31