您好,登錄后才能下訂單哦!
這篇文章主要介紹“JS前端性能指標(biāo)定位FMP如何使用”的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“JS前端性能指標(biāo)定位FMP如何使用”文章能幫助大家解決問(wèn)題。
可能大家對(duì)「白屏?xí)r間」這個(gè)名詞并不陌生,他是「刀耕火種」年代,我們收集的頁(yè)面性能指標(biāo)之一,隨著前端工程的復(fù)雜化,白屏?xí)r間已經(jīng)沒(méi)有什么實(shí)質(zhì)性的意義了,取而代之的就是 FMP。
先來(lái)介紹幾個(gè)與之相關(guān)的名詞。
FP(First Paint):首次繪制,標(biāo)記瀏覽器渲染任何在視覺(jué)上不同于導(dǎo)航前屏幕內(nèi)容的時(shí)間點(diǎn)
FCP(First Contentful Paint):首次內(nèi)容繪制,標(biāo)記的是瀏覽器渲染第一針內(nèi)容 DOM 的時(shí)間點(diǎn),該內(nèi)容可能是文本、圖像、SVG 或者 <canvas>
等元素
FMP(First Meaning Paint):首次有效繪制,標(biāo)記主角元素渲染完成的時(shí)間點(diǎn),主角元素可以是視頻網(wǎng)站的視頻控件,內(nèi)容網(wǎng)站的頁(yè)面框架也可以是資源網(wǎng)站的頭圖等。
相對(duì)于 FP 和 FCP,F(xiàn)MP 是我們前端最常關(guān)注的重要性能指標(biāo),Google 定義它為「是否有用?」的時(shí)間點(diǎn)。然而,「是否有用?」是很難以通用方式界定的,因此,至今依然沒(méi)有標(biāo)準(zhǔn)的 API 輸出。
社區(qū)中常有這么幾種方式進(jìn)行「相對(duì)準(zhǔn)確」的計(jì)算 FMP,所謂相對(duì)準(zhǔn)確,是相對(duì)于實(shí)際項(xiàng)目而言。
主動(dòng)上報(bào):開(kāi)發(fā)者在相應(yīng)頁(yè)面的「Meaning」位置上報(bào)時(shí)間
權(quán)重計(jì)算:根據(jù)頁(yè)面元素,計(jì)算權(quán)重最高的元素渲染時(shí)間
趨勢(shì)計(jì)算:在 render 期間,根據(jù) dom 的變化趨勢(shì)推算 FMP 值
本文將著重介紹第二種方式。
所謂權(quán)重,即,將頁(yè)面的元素以約定的「權(quán)重比」遍歷出「權(quán)重值」最大的某一個(gè)或一組 DOM,然后以其「裝載時(shí)間點(diǎn)」或「加載結(jié)束點(diǎn)」作為 FMP 的映射。
想要對(duì) DOM 節(jié)點(diǎn)進(jìn)行階段性標(biāo)記,就得有監(jiān)聽(tīng) DOM 變化的能力,慶幸的是,HTML5 賦予了我們這個(gè)能力。
MutationObserver
,Mutation Events功能的替代品,是DOM3 Events規(guī)范的一部分。他可以在指定的 DOM 發(fā)生變化時(shí)執(zhí)行回調(diào)。
MutationObserver 有三個(gè)方法
disconnect() 阻止 MutationObserver 實(shí)例繼續(xù)接收的通知,直到再次調(diào)用其observe()方法,該觀(guān)察者對(duì)象包含的回調(diào)函數(shù)都不會(huì)再被調(diào)用。
observe() 配置MutationObserver在DOM更改匹配給定選項(xiàng)時(shí),通過(guò)其回調(diào)函數(shù)開(kāi)始接收通知。
takeRecords() 從MutationObserver的通知隊(duì)列中刪除所有待處理的通知,并將它們返回到MutationRecord對(duì)象的新Array中。
global.mo = new MutationObserver(() => { /* callback: DOM 節(jié)點(diǎn)設(shè)置階段性標(biāo)記 */ }); /** * mutationObserver.observe(target[, options]) * target - 需要觀(guān)察變化的 DOM Node。 * options - MutationObserverInit 對(duì)象,配置需要觀(guān)察的變化項(xiàng)。 * 更多 options 的介紹請(qǐng)參考 https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserverInit#%E5%B1%9E%E6%80%A7 **/ global.mo.observe(document, { childList: true, // 監(jiān)聽(tīng)子節(jié)點(diǎn)變化(如果subtree為true,則包含子孫節(jié)點(diǎn)) subtree: true // 整個(gè)子樹(shù)的所有節(jié)點(diǎn) });
下圖粗濾的解析了正常單頁(yè)面的渲染過(guò)程
預(yù)備階段:導(dǎo)航階段,處在連接相應(yīng)的過(guò)程
階段一:首字節(jié)渲染階段,也是FCP,DOM 樹(shù)的第一次有效變化
階段二:基本框架渲染完成
階段三:獲取到數(shù)據(jù),渲染到視圖上
階段四:圖片加載完成,加載過(guò)程不被標(biāo)記
實(shí)際上在第一、第三階段之間還存在著大量的 DOM 變化,Mutation Observer 事件的觸發(fā)并不是同步的,而是異步觸發(fā)的,也就是說(shuō),等到當(dāng)前「階段」所有 DOM 操作都結(jié)束才觸發(fā)。
Mutation Observer 有以下特點(diǎn)
它等待所有腳本任務(wù)完成后,才會(huì)運(yùn)行(即異步觸發(fā)方式)。
它把 DOM 變動(dòng)記錄封裝成一個(gè)數(shù)組進(jìn)行處理,而不是一條條個(gè)別處理 DOM 變動(dòng)。
它既可以觀(guān)察 DOM 的所有類(lèi)型變動(dòng),也可以指定只觀(guān)察某一類(lèi)變動(dòng)。
在 load
事件觸發(fā)后,各個(gè)階段的 tag 已經(jīng)被打到標(biāo)簽上了
此處以『_ti
』昨晚標(biāo)記 key。
在打標(biāo)記的同時(shí),需要記錄下當(dāng)前的時(shí)間節(jié)點(diǎn),備用
// 偽代碼 function callback() { global.timeStack[++_ti] = performance.now(); // 記時(shí)間 doTag(_ti); // 打標(biāo)記 }
標(biāo)記打完后就等 load 的那一刻進(jìn)行計(jì)算反推了。
一般來(lái)說(shuō)
視圖占比越大的元素越有可能是主角元素
視頻比圖片更可能是主角元素
svg
和 canvas
也很重要
其他元素都可以按普通 dom 計(jì)算了
背景圖片視情況而定,可記可不記
// 偽代碼 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]; // 約定好的權(quán)重比 let weight = width * height * wts; // 直接乘,或者更細(xì)粒度的計(jì)算 wts(width, height, wts) return { weight, wts, tagName: node.tagName, ti: node.getAttribute("_ti"), node }; }
在我們的約定權(quán)重算法下,權(quán)重最大的元素即為我們推到的主角元素。
// 偽代碼 function getCoreNode(node){ let list = nodeTraversal(node); // 遞歸計(jì)算每個(gè)標(biāo)記節(jié)點(diǎn)的權(quán)重值 return getNodeWithMaxWeight(list); // weight 最大的元素 }
不同的元素獲取時(shí)間的方式并不相同
普通元素:按標(biāo)記點(diǎn)時(shí)間計(jì)算
圖片和視頻:按資源相應(yīng)結(jié)束時(shí)間計(jì)算
帶背景元素:可以以背景資源相應(yīng)結(jié)束時(shí)間計(jì)算,也可以按普通元素計(jì)算
// 偽代碼 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 頁(yè)為例,類(lèi)似的電商網(wǎng)站,我們希望拿到「階段二」或「階段三」的時(shí)間點(diǎn)作為我們的 FMP 值。
因?yàn)槲覀儾⒉幌M钢鹘窃亍沟谋尘盎蛘摺笀D片主角元素」的相應(yīng)時(shí)間算在 FMP 的值內(nèi),所以,我們將「圖片」「視頻」等資源元素降級(jí)成普通元素計(jì)算。
在 Chrome [ Disable cache / Fast 3G ] 條件下我們進(jìn)行模擬驗(yàn)證。
計(jì)算得到的 FMP 值為 4730.7ms,Chrome Performance 監(jiān)控的值在 4950ms 左右,誤差在 200ms 左右。
如果將限速放開(kāi),F(xiàn)MP 的取值將更接近我們希望的「First Meaning Paint」。
關(guān)于“JS前端性能指標(biāo)定位FMP如何使用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。