您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“FMP節點監控相對準確的計算方法是什么”,內容詳細,步驟清晰,細節處理妥當,希望這篇“FMP節點監控相對準確的計算方法是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
MutationObserver
一句話解釋
「MutationObserver 給予我們獲取 DOM 渲染「切面」的能力」。
「MDN 解釋」MutationObserver 接口提供了監視對 DOM 樹所做更改的能力。它被設計為舊的 Mutation Events 功能的替代品,該功能是 DOM3 Events 規范的一部分。
有了以上能力,既可以對節點進行監聽和 「標記」
像這樣
// 偽代碼 new MutationObserver(() => { let timestamp = performance.now() || (Date.now() - START_TIME), doTag(document.body, global.paintTag++); global.ptCollector.push(timestamp); });
名詞解釋: - paintTag:對應 dom 的打點標記「_pi」,標記著第幾次配渲染的產物。
ptCollector:paintTag 對應的時間節點集合。可以用 paintTag 檢索到某次渲染時刻的時間節點。
window.load 開始計算
我們認為,通常情況下,在 window 觸發 load 事件的時刻,意味著主要業務的 90% 的資源和 dom 都已經準備就緒。此時算出的高權重得分的 dom 就是我們想要找的 FMP 關鍵節點。
我不關心你是怎么渲染的,異步也好直出也好,殊途同歸,我只關心結果
一個基礎節點(無子節點)的權重得分計算方法:
// 偽代碼 const TAG_WEIGHT_MAP = { SVG: 2, IMG: 2, CANVAS: 2, VIDEO: 4 }; node => { let weight = TAG_WEIGHT_MAP[node.tagName], areaPercent = global.calculateShowPercent(node); let score = width * height * weight * areaPercent; return score; }
這是一個算法我把它叫做「代父競選」
父節點自身的權重得分計算方法同基礎節點相同,不同的是,如果其子節點的得分和大于或等于了自身的得分,將由子節點組代替父節點參與更高級的競選,同時,子節點的權重得分和作為父節點的得分,另外,如果子節點是有孫子節點代表的,孫子節點將會同步升級。
怎么理解呢?
如下兩種情況:
一
父元素得分 = 400 * 100 = 40000 子元素得分和 = 300 * 60 + 60 * 60 = 21600 父元素得分 > 子元素得分和
此情況下,該組元素以 40000 的得分進入下一級競選。參選的元素列表為父元素本身。
數據結構如下:
{ deeplink: [{…}], elements: [{ node: parent#id_search, ... }], node: parent#id_search, paintIndex: 1, score: 40000 }
二
父元素得分 = 400 * 300 = 120000 子元素得分和 = 400 * 300 + 60 * 100 = 126000 父元素得分 < 子元素得分和
此情況下,該組元素應以 126000 的得分進入下一級競選。參選的元素列表為子元素組,「代父競選」。
數據結構如下:
{ deeplink: [{…}], elements: [ {node: child#id_slides_pics, ...}, {node: child#id_slides_index, ...} ], node: parent#id_slides, paintIndex: 2, score: 126000 }
由以上兩種情況可推
父元素得分 = 400 * 400 = 160000 子元素得分和 = 40000 + 126000 = 166000 父元素得分 < 子元素得分和 其中一個子節點由孫子節點們代表
==>
{ deeplink: [{…}], elements: [ {node: child#id_search, ...}, {node: child#id_slides_pics, ...}, {node: child#id_slides_index, ...} ], node: parent#id_body, paintIndex: 1, score: 166000 }
所以,以下組合與拆分就不難理解了。
在我們對 document 深度遍歷計算的過程中,總會遇到一些干擾因素使我們的腳本計算出錯,以下兩種就是最常見的
這種元素雖然用戶無感知,但會嚴重影響最后的競選結果。
const isIgnoreDom = node => { return getStyle(node, 'opacity') < 0.1 || getStyle(node, 'visibility') === 'hidden' || getStyle(node, 'display') === 'none' || node.children.length === 0 && getStyle(node, 'background-image') === 'none' && getStyle(node, 'background-color') === 'rgba(0, 0, 0, 0)'; }
首先我們認為opacity < 0.1
visibility === 'hidden'
和 display === 'none'
的元素為不可見元素,應忽略,另外,無子節點,且無背景無顏色的元素也歸屬于不可見元素,忽略。
由于我們的腳本在 window load 后才執行,絕大情況下此時瀏覽器的滾動條已經發生了偏移。精選結果會發生誤差。如下圖:
此時精選結果為
<div class="channel" _pi="30">...</div>
_pi 走到了 30,「第 30 次渲染」,無論有多快,這個值始終會遠大于實際的 FMP。
導致「滾動偏移」的情況有兩種
在 load
觸發前用戶主動翻閱 這種情況再常見不過,用戶不可能每次都等到 load 后才進行操作。而且如果存在 pending
的資源,load 的時間會非常遲。
load
瀏覽器觸發前執行了「scrollRestore (英文描述,并不存在此事件)」
對于第二種情況,還是很好解的,因為并不是所有的瀏覽器都有 History.scrollRestoration 的特效,所以,我們只要關掉即可,但情況一我們是無論如何不能控制的。
所以,只能另辟蹊徑「劃定計算區域」,且此區域應避開滾動條位置的影響。
當然,我們也是有方法的,其實也挺簡單。
這得益于「document 對象的寬高是固定的,且偏移量同步于滾動條」
const getDomBounding = dom => { const { x, y } = document.body.getBoundingClientRect(); const { left, right, top, bottom, width, height } = dom.getBoundingClientRect(); return { left: left - x, right: right - x, top: top - y, bottom: bottom - y, height, width } }
像 <DIV/>
、<SPAN/>
、<P/>
、<INPUT/>
這些普通元素,標注的 _pi 值索引到的渲染時刻的時間節點 ptCollector
還記得嗎?該時間即可作為 FMP 值。
有特殊情況,如果普通元素帶有背景圖片,則會升級為 <IMG/>
類資源元素
如 <IMG/>
、<VIDEO/>
,該元素的 resource 的 responseEnd
的時間節點將作為 FMP 值
不過,我們可以針對不同的項目對全局權重配置 TAG_WEIGHT_MAP
做「合理化」調整。當然也可以忽略「圖片」和「視頻」等資源元素資源加載時間,一切以實際項目而定
讀到這里,這篇“FMP節點監控相對準確的計算方法是什么”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。