性能優化是全部前端人的追求,在這條路上,方法多種多樣。這篇文章,說一下能夠怎樣定義性能指標及上報。javascript
FP,全稱 First Paint,翻譯爲首次繪製,是時間線上的第一個時間點,它表明網頁的第一個像素渲染到屏幕上所用時間,也就是頁面在屏幕上首次發生視覺變化的時間。html
統計邏輯前端
經過performance.getEntriesByType('paint’),取第一個pain的時間。如:java
function getFPTime(){ const timings = performance.getEntriesByType('paint')[0]; return timings ? Math.round(timings.startTime) : null }
FCP,全稱 First Contentful Paint,翻譯爲首次內容繪製,顧名思義,它表明瀏覽器第一次向屏幕繪內容。node
注意:只有首次繪製文本、圖片(包含背景圖)、非白色的canvas或SVG時才被算做FCP。web
經過performance.getEntriesByType('paint’),取第二個pain的時間,或者經過Mutation Observer觀察到首次節點變更的時間。如:npm
const domEntries = [] const observer = new MutationObserver((mutationsList)=>{ for(var mutation of mutationsList) { if (mutation.type == 'childList') { console.log('A child node has been added or removed.'); } if (mutation.type == 'addedNodes') { //TODO新增了節點,作處理,計算此時的可見性/位置/出現時間等信息,而後 push 進數組 ... domEntries.push(mutation) } } }); function getFPTime(){ const timings = performance.getEntriesByType('paint'); if(timings.length > 1)return timings[1] return timings ? Math.round(timings.startTime) : null //僞代碼,算 DOM 變化時的最小那個時間,即節點首次變更的時間 return Math.round(domEntries.length ? Math.min(...domEntries.map(entry => entry.time)) : 0); }
MutationObserver 理解及使用補充:canvas
FP與FCP這兩個指標之間的主要區別是:FP是當瀏覽器開始繪製內容到屏幕上的時候,只要在視覺上開始發生變化,不管是什麼內容觸發的視覺變化,在這一刻,這個時間點,叫作FP。數組
相比之下,FCP指的是瀏覽器首次繪製來自DOM的內容。例如:文本,圖片,SVG,canvas元素等,這個時間點叫FCP。瀏覽器
FP和FCP多是相同的時間,也多是先FP後FCP。
FMP,全稱 First Meaningful Paint,翻譯爲首次有意義的繪製,是頁面主要內容出如今屏幕上的時間, 這是用戶感知加載體驗的主要指標。目前尚無標準化的定義, 由於很難以通用的方式去肯定各類類型頁面的關鍵內容。
目前沒有統一邏輯,阿里有個標準爲最高可見增量元素,採用深度優先遍歷方法,詳細可見:https://zhuanlan.zhihu.com/p/44933789
其次,能夠自定義,好比通 Mutation Observer 觀察頁面加載的一段時間(如前20s)內頁面節點的變化, 即元素新增/移除/隱藏等變化記錄下來,這樣能夠獲得頁面元素的可見時間點及元素與可視區域的交叉信息等。
而後,自定義一個計算公式,好比根據元素的類型進行權重取值(div 權重1,img 權重2等), 而後取元素與可視區域的交叉區域面積、可見度、 權重值之間的乘積爲元素評分。
根據上面獲得的信息, 以時間點爲X軸, 該時間點可見元素的評分總和爲Y軸, 取最高點對應的最小時間爲頁面主要內容出如今屏幕上的時間。
FID,全稱 First Input Delay,翻譯爲首次輸入延遲,是測量用戶首次與您的站點交互時的時間(即當他們單擊連接/點擊按鈕/使用自定義的JavaScript驅動控件時)到瀏覽器實際可以迴應這種互動的時間。
方式一,經過performanceObserver(目前支持性爲88.78%)觀察類型爲first-input的entry,得到其startTime/duration等數便可
方式二,初始化時爲特定事件類型(click/touch/keydown)綁定通用統計邏輯事件,開始調用時從event.timeStamp取開始處理的時間(這個時間就是首次輸入延遲時間),在事件處理中註冊requestIdleCallback事件回調onIdleCallback,當onIdleCallback被執行時,當前時間減開始的event.timeStamp即爲duration時間
參考代碼:
// 方式一 function getFIDTime(){ const timings = performance.getEntriesByType('first-input')[0]; return timings ? timings : null } // 方式二,如下代碼僅表明思路 ['click','touch','keydown'].forEach(eventType => { window.addEventListener(eventType, eventHandle); }); function eventHandle(e) { const eventTime = e.timeStamp; window.requestIdleCallback(onIdleCallback.bind(this, eventTime, e)); } function onIdleCallback(eventTime, e) { const now = window.performance.now(); const duration = now - eventTime; return { duration: Math.round(duration), timestamp: Math.round(eventTime) } ['click','touch','keydown'].forEach(eventType => { window.removeEventListener(eventType, eventHandle); }); }
Event 對象的更多理解:https://developer.mozilla.org/zh-CN/docs/Web/API/Event
TTI,全稱 Time To Interactive,翻譯爲可交互時間,指的是應用在視覺上都已渲染出了,徹底能夠響應用戶的輸入了。是衡量應用加載所需時間並可以快速響應用戶交互的指標
與 FMP 相同,很難規範化適用於全部網頁的 TTI 指標定義。
統計方式一:谷歌實驗室寫的npm包,tti-polyfill
import ttiPolyfill from 'tti-polyfill'; ttiPolyfill.getFirstConsistentlyInteractive().then((tti) => { ga('send', 'event', { eventCategory:'Performance Metrics', eventAction:'TTI', eventValue: tti, nonInteraction: true, }); });
統計方式二:在頁面加載的必定時間內(如前50s內),以(domContentLoadedEventStart-navigationStart)+5爲起始點,循環尋找,找到一個5s的窗口,其中網絡請求不超過2個且沒有長任務(>50ms),再找到該5秒窗口以前的最後一個長任務,該長任務結束的時間點就是可穩定交互時間。其中長任務可自定義時間或通performance.getEntriesByType('long-task')獲取
// 如下代碼僅表明思路 const basicTime = 5000; function getTTITime(startTime,longTaskEntries, resourceEntries,domContentLoadedTime) { let busyNetworkInWindow = []; let tti = startTime; while (startTime + basicTime <= 50000) { //從前50s 中去找 tti = startTime; longTasksInWindow = longTaskEntries.filter(task => { return task.startTime < startTime + basicTime && task.startTime + task.duration > startTime; }); if (longTasksInWindow.length) { const lastLongTask = longTasksInWindow[longTasksInWindow.length - 1]; startTime = lastLongTask.startTime + lastLongTask.duration; continue; } busyNetworkInWindow = resourceEntries.filter(request => { return !(request.startTime >= startTime + basicTime || request.startTime + request.duration <= startTime); }); if (busyNetworkInWindow.length > 2) { const firstRequest = busyNetworkInWindow[0]; startTime = firstRequest.startTime + firstRequest.duration; continue; } return Math.max(tti, domContentLoadedTime); } return Math.max(tti, domContentLoadedTime); }
FCI,全稱 First CPU Idle,翻譯爲首次CPU空閒時間表明着一個網頁已經知足了最小程度的與用戶發生交互行爲的時刻。當咱們打開一個網頁,咱們並不須要等到一個網頁徹底加載好了,每個元素都已經完成了渲染,而後再去與網頁進行交互行爲。網頁知足了咱們基本的交互的時間點是衡量網頁性能的一個重要指標。
FCI爲在FMP以後,首次在必定窗口時間內沒有長任務發生的那一時刻,而且若是這個時間點早於DOMContentLoaded時間,那麼FCI的時間爲DOMContentLoaded時間,窗口時間的計算函數能夠根據Lighthouse提供的計算公式 N = f(t) = 4 e^(-0.045 t) + 1 進行自定義設計
FPS,全稱 Frames Per Second,翻譯爲每秒幀率,表示的是每秒鐘畫面更新次數,當今大多數設備的屏幕刷新率都是60次/秒。
參考標準:
利用requestAnimationFrame,循環調用,當now大於lastTime+1S時,計算FPS。若小於某個閥值則能夠認爲當前幀率較差,若連續小於多個閥值,則中止統計,當前頁面處於卡頓狀態,進入卡頓處理邏輯
更多具體參考:
從window.navigator.userAgent中能夠獲取用戶設備信息,如圖:
從window.navigator.connection中能夠獲取設備網絡信息,如:
從window.devicePixelRatio能夠獲取設備像素比。
pv/uv
監聽各類頁面切換的狀況;SPA頁面,能夠監聽hashChange
性能數據/設備信息/網絡情況
用圖說話,本文內容,整理到了一張圖上。
前端性能優化之自定義性能指標及上報方法詳解
前端性能優化之利用 Chrome Dev Tools 進行頁面性能分析
Chrome 頁面呈現原理與性能優化之企業級分享總結(內附完整ppt)