JS前端性能指標定位FMP使用詳解
什么是FMP?
可能大家對「白屏時間」這個名詞并不陌生,他是「刀耕火種」年代,我們收集的頁面性能指標之一,隨著前端工程的復雜化,白屏時間已經(jīng)沒有什么實質(zhì)性的意義了,取而代之的就是 FMP。
先來介紹幾個與之相關的名詞。
- FP(First Paint):首次繪制,標記瀏覽器渲染任何在視覺上不同于導航前屏幕內(nèi)容的時間點
- FCP(First Contentful Paint):首次內(nèi)容繪制,標記的是瀏覽器渲染第一針內(nèi)容 DOM 的時間點,該內(nèi)容可能是文本、圖像、SVG 或者
<canvas>
等元素 - FMP(First Meaning Paint):首次有效繪制,標記主角元素渲染完成的時間點,主角元素可以是視頻網(wǎng)站的視頻控件,內(nèi)容網(wǎng)站的頁面框架也可以是資源網(wǎng)站的頭圖等。
相對于 FP 和 FCP,F(xiàn)MP 是我們前端最常關注的重要性能指標,Google 定義它為「是否有用?」的時間點。然而,「是否有用?」是很難以通用方式界定的,因此,至今依然沒有標準的 API 輸出。
社區(qū)中常有這么幾種方式進行「相對準確」的計算 FMP,所謂相對準確,是相對于實際項目而言。
- 主動上報:開發(fā)者在相應頁面的「Meaning」位置上報時間
- 權重計算:根據(jù)頁面元素,計算權重最高的元素渲染時間
- 趨勢計算:在 render 期間,根據(jù) dom 的變化趨勢推算 FMP 值
本文將著重介紹第二種方式。
權重定位
所謂權重,即,將頁面的元素以約定的「權重比」遍歷出「權重值」最大的某一個或一組 DOM,然后以其「裝載時間點」或「加載結(jié)束點」作為 FMP 的映射。
權重計算
節(jié)點標記
想要對 DOM 節(jié)點進行階段性標記,就得有監(jiān)聽 DOM 變化的能力,慶幸的是,HTML5 賦予了我們這個能力。
MutationObserver
,Mutation Events功能的替代品,是DOM3 Events規(guī)范的一部分。他可以在指定的 DOM 發(fā)生變化時執(zhí)行回調(diào)。
MutationObserver 有三個方法
- disconnect() 阻止 MutationObserver 實例繼續(xù)接收的通知,直到再次調(diào)用其observe()方法,該觀察者對象包含的回調(diào)函數(shù)都不會再被調(diào)用。
- observe() 配置MutationObserver在DOM更改匹配給定選項時,通過其回調(diào)函數(shù)開始接收通知。
- takeRecords() 從MutationObserver的通知隊列中刪除所有待處理的通知,并將它們返回到MutationRecord對象的新Array中。
global.mo = new MutationObserver(() => { /* callback: DOM 節(jié)點設置階段性標記 */ }); /** * mutationObserver.observe(target[, options]) * target - 需要觀察變化的 DOM Node。 * options - MutationObserverInit 對象,配置需要觀察的變化項。 * 更多 options 的介紹請參考 https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserverInit#%E5%B1%9E%E6%80%A7 **/ global.mo.observe(document, { childList: true, // 監(jiān)聽子節(jié)點變化(如果subtree為true,則包含子孫節(jié)點) subtree: true // 整個子樹的所有節(jié)點 });
下圖粗濾的解析了正常單頁面的渲染過程
- 預備階段:導航階段,處在連接相應的過程
- 階段一:首字節(jié)渲染階段,也是FCP,DOM 樹的第一次有效變化
- 階段二:基本框架渲染完成
- 階段三:獲取到數(shù)據(jù),渲染到視圖上
- 階段四:圖片加載完成,加載過程不被標記
實際上在第一、第三階段之間還存在著大量的 DOM 變化,Mutation Observer 事件的觸發(fā)并不是同步的,而是異步觸發(fā)的,也就是說,等到當前「階段」所有 DOM 操作都結(jié)束才觸發(fā)。
Mutation Observer 有以下特點
- 它等待所有腳本任務完成后,才會運行(即異步觸發(fā)方式)。
- 它把 DOM 變動記錄封裝成一個數(shù)組進行處理,而不是一條條個別處理 DOM 變動。
- 它既可以觀察 DOM 的所有類型變動,也可以指定只觀察某一類變動。
在 load
事件觸發(fā)后,各個階段的 tag 已經(jīng)被打到標簽上了
此處以『_ti
』昨晚標記 key。
在打標記的同時,需要記錄下當前的時間節(jié)點,備用
// 偽代碼 function callback() { global.timeStack[++_ti] = performance.now(); // 記時間 doTag(_ti); // 打標記 }
標記打完后就等 load 的那一刻進行計算反推了。
計算權重值
一般來說
- 視圖占比越大的元素越有可能是主角元素
- 視頻比圖片更可能是主角元素
svg
和canvas
也很重要- 其他元素都可以按普通 dom 計算了
- 背景圖片視情況而定,可記可不記
第一步:簡單粗暴,按大小計算
// 偽代碼 function weightCompute(node){ let { width, height, left, top } = node.getBoundingClientRect(); // 排除視圖外的元素 if(isOutside(width, height, left, top)){ return 0; } let wts = TAG_WEIGHT_MAP[node.tagName]; // 約定好的權重比 let weight = width * height * wts; // 直接乘,或者更細粒度的計算 wts(width, height, wts) return { weight, wts, tagName: node.tagName, ti: node.getAttribute("_ti"), node }; }
第二步:根據(jù)權重值推導主角元素
在我們的約定權重算法下,權重最大的元素即為我們推到的主角元素。
// 偽代碼 function getCoreNode(node){ let list = nodeTraversal(node); // 遞歸計算每個標記節(jié)點的權重值 return getNodeWithMaxWeight(list); // weight 最大的元素 }
第三步:根據(jù)元素類型取時間
不同的元素獲取時間的方式并不相同
- 普通元素:按標記點時間計算
- 圖片和視頻:按資源相應結(jié)束時間計算
- 帶背景元素:可以以背景資源相應結(jié)束時間計算,也可以按普通元素計算
// 偽代碼 function getFMP(){ let coreObj = getCoreNode(document.body), fmp = -1; let { tagName, ti, node } = coreObj; switch(tagName){ case 'IMG': case 'VIDEO': let source = node.src; let { responseEnd } = performance.getEntries().find(item => item.name === source); fmp = responseEnd || -1; break; default: if(node.style.backgroundImage){ // 普通元素的背景處理 }else{ fmp = global.timeStack[+ti]; } } return fmp; }
回歸驗證
以我們的 demo 頁為例,類似的電商網(wǎng)站,我們希望拿到「階段二」或「階段三」的時間點作為我們的 FMP 值。
因為我們并不希望「主角元素」的背景或者「圖片主角元素」的相應時間算在 FMP 的值內(nèi),所以,我們將「圖片」「視頻」等資源元素降級成普通元素計算。
在 Chrome [ Disable cache / Fast 3G ] 條件下我們進行模擬驗證。
計算得到的 FMP 值為 4730.7ms,Chrome Performance 監(jiān)控的值在 4950ms 左右,誤差在 200ms 左右。
如果將限速放開,F(xiàn)MP 的取值將更接近我們希望的「First Meaning Paint」。
以上就是JS前端性能指標定位FMP使用詳解的詳細內(nèi)容,更多關于JS前端性能指標定位FMP的資料請關注腳本之家其它相關文章!
相關文章
微信小程序組件 contact-button(客服會話按鈕)詳解及實例代碼
這篇文章主要介紹了微信小程序組件 contact-button(客服會話按鈕)詳解及實例代碼的相關資料,需要的朋友可以參考下2017-01-01umi插件開發(fā)仿dumi項目自動生成導航欄實現(xiàn)詳解
這篇文章主要為大家介紹了umi插件開發(fā)仿dumi項目自動生成導航欄實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01sessionStorage多Tab標簽頁數(shù)據(jù)共享問題分析
這篇文章主要為大家介紹了sessionStorage多Tab標簽頁數(shù)據(jù)共享問題分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07jQuery單頁面文字搜索插件jquery.fullsearch.js的使用方法
jquery.fullsearch.js是一款基于Bootstrap文字搜索插件,可以幫助您快速搜索到當前頁面所包含的指定文字,并定位到所在位置2020-02-02JavaScript實現(xiàn)余額數(shù)字滾動效果
這篇文章主要介紹了JavaScript實現(xiàn)余額數(shù)字滾動效果,將傳入的帶滾動的n位數(shù)字拆分成每一個要滾動的數(shù),然后動態(tài)的創(chuàng)建裝著滾動到每一位相應數(shù)字的容器,然后放入傳入的目標容器中,更多詳細內(nèi)容,一起進入下面文章學習吧2021-12-12