作者:京東科技 郝樑
前言:作為 C 端前端研發,除了攻克業務難點以外,也要有更深層的自我目標,那就是效能優化。這事兒說大不大,說小也不小,但難度絕對不一般,所涉及的範圍優化點深入工程每個細胞。做好前端效能優化絕非簡單之事!文章主要內容介紹前端效能考核指標及優化方案。
根據 chrome Lighthouse 最新規則,前端效能指標考量主要有 FCP(First Contenful Paint)、SI(Speed Index)、LCP(Largest Contentful Paint)、TBT(Total Blocking Time)、CLS(Cumulative Layout Shift) ,佔比分別如下。
FCP: First Contentful Paint 首次內容繪製是指測量頁面從開始載入到頁面內容(文字、圖片、背景圖、svg 元素或非白色 canvas 元素)的任何部分在螢幕上完成渲染的時間,是測量載入速度感知的重要指標之一。
範例:
從上圖可以觀察到,頁面載入開始到頁面渲染完成的時間軸中,FCP 發生在第二幀,首批文字和圖片在螢幕上已經渲染完成。
雖然頁面一部分內容已完成渲染,但這並非頁面所有內容全部完成渲染;這就是首次內容繪製(FCP)與最大內容繪製(LCP)最重要的區別。
FCP 效能值:首次內容繪製完成渲染時間應控制在 1.8s 以內。
我們可以從以下方向點優化 FCP :
SI:Speed Index 衡量頁面載入期間內容以視覺方式顯示的速度。 Lighthouse 首先捕獲瀏覽器中頁面載入的視訊,並計算幀之間的視覺速度。通俗的講,就是網頁從有東西到完全顯示內容的可見填充速度。
Speed Index 指標值:
我們可以從以下方向點優化 Speed Index 的方法:
LCP: Largest Contentful Paint 最大(最有意義)內容繪製,是指根據頁面首次開始載入的時間點來報告可視區域內可見的最大影象或者文字塊完成渲染的相對時間。
LCP 指標值:
主要考量以下幾種相關元素:
最大內容繪製(LCP)的元素大小是指使用者在可視區域內可見的大小,所以考量都是基於可視區域為準,如果元素有延伸到可視區域外,或者元素被裁剪或包含不可見的溢位,這些部分不計入元素大小;
對於影象元素的大小,指標會對比可見尺寸與原始尺寸,取尺寸小者為準;例如雙倍圖以可見尺寸為準,拉伸放大圖則以原始尺寸為準;
對於文字元素,元素的大小為文位元組點的大小(包含所有文位元組點的最小矩形);
WARNING: 所有元素通過 CSS 設定的任何邊距、填充或邊框都不在考量範圍內。另外如果設定了滿屏背景圖,但螢幕可視區域內有佔比較大的元素(浮在背景圖上的元素),導致背景圖暴漏可視範圍較小,那麼最大內容會選擇可視區域內最大元素。
並且,一個元素只有在渲染完成後對使用者可見後才能視為最大內容元素。
因為網路或技術原因,網頁的載入通常是分段進行的, 所以最大元素也在發生變化。
為了應對這種變化,瀏覽器在繪製第一幀後立即分發一個 largest-contentful-paint 型別的 PerformanceEntry (代表了 performance 時間列表中單個 metric 資料;performance.getEntries() 獲取時間列表資料),用於識別最大內容元素。渲染後續幀之後,瀏覽器會在最大內容元素髮生變化時分發另一個 PerformanceEntry 。
頁面的元素(某一個元素)只有在渲染完成後並且對使用者可見後才能視為最大內容元素。未載入的影象不會視為渲染完成,也就不能視為最大內容元素。字型阻塞期使用字型的文字也是如此。這些情況下,較小的元素會被報告為最大的元素,但一旦更大的元素渲染完成,則會上報另一個 PerformanceEntry 物件。
除了延遲載入的影象與字型外,頁面可能會在新內容(介面請求等)可用時向 DOM 新增新元素內容。如果有一個新元素大於先前的最大內容元素,則瀏覽器還會上報一個新的 PerformanceEntry 物件。
如果當前的最大內容元素從可視區域被移除(甚至從 DOM 中被移除),那麼除非有一個更大的元素完成渲染,否則該元素將持續作為最大內容元素,不會更改 performanceEntry 物件。
當用戶與頁面進行互動(通過輕觸、捲動或按鍵)時,瀏覽器將立即停止上報 PerformanceEntry 物件,因為使用者互動通常會改變頁面原有內容。
瀏覽器出於安全考慮,對於缺少 Timing-Allow-Origin 檔頭的跨域物件來說,是無法得到影象渲染時間戳的,只有影象載入時間戳。正確的設定 Timing-Allow-Origin 檔頭,可以獲取更準確的指標值。
情況1:對元素大小或位置修改不會生成新的 LCP 候選物件,只有元素在可視區域內的初始大小和位置會被納入考量範圍;
情況2:最初在可視範圍內渲染,然後被移除可視區域外的元素仍將報告他在可視區域內的初始大小;
情況3:而在螢幕可視範圍外渲染完成,過度到螢幕上的元素則不做報告。
範例:最大元素隨著內容載入完成而發生改變
第一個範例中,新內容渲染完成,因此使最大元素髮生了改變。
第二個範例中,由於佈局的改變,先前的最大內容從可視區域中被移除了。
如果延遲內容沒有初始最大元素大,則 LCP 取初始值。
頁面上最重要元素並非最大元素,這個時候開發者考核指標是最重要元素。
影響頁面渲染效能主要原因有以下幾點,通過優化它們可以降低 LCP 指標值
是指瀏覽器從伺服器接收內容所需的時間越長,使用者在螢幕上所渲染內容的時間就越長。更快的伺服器將直接影響包括 LCP 各項指標的載入值。
可優化方向:
瀏覽器渲染內容之前需要先解析 DOM 樹,解析過程中,如果遇到任何外部樣式表(<link rel="stylesheet">)或同步 JavaScript 標籤(<script src="main.js">),則會暫停解析。
所以指令碼跟樣式都是阻塞渲染的資源,這些資源都會導致 FCP 延遲,從而導致 LCP 延遲。所以延遲載入非必要的 JS 和 CSS ,從而提高網頁主要內容載入速度。
減少 CSS 阻塞時間的方法:
減少阻塞渲染的 JavaScript 數量能夠讓渲染速度更快,降低 LCP 值
減少 JS 阻塞時間的方法:
雖然 CSS 或 JavaScript 阻塞時間的增加會直接導致效能下降,但載入許多其他型別資源所需的時間也會影響繪製時間。
影響 LCP 的元素有以下幾種:
優化方法:
如 React 、 Vue 、 Angular 這類框架所搭建的單頁面應用,是完全在使用者端中處理邏輯的。
優化方法:
TBT: Total Blocking Time 總阻塞時間,是頁面被阻塞響應使用者互動的總時間。 TBT = LCP (首次最大內容繪製)和可互動時間之間所有長時間任務的阻塞部分之和。是測量頁面載入響應的重要指標。
超過 50 毫秒的任務即為長任務。 超出 50 毫秒的時間量為阻塞部分。
例如:檢測到一個 90 毫秒的任務,則阻塞部分為 40 毫秒(90 - 50 = 40)
TBT 指標:
優化方法:
CLS: 累計佈局偏移(CLS)是測量視覺穩定性的重要指標。是整個頁面宣告週期內發生的所有意外佈局偏移中最大一連串的佈局偏移分數。
頁面內容的意外偏移大多是由於非同步資源載入,或者動態新增 DOM 元素到頁面現有內容上方導致的。罪魁禍首可能是未知尺寸的影象或視訊、實際渲染後比後備字型更大或更小的字型等。
CLS 指標:
注意: 只有當現有元素的起始位置發生變更時才算做佈局偏移。如果將新元素新增到 DOM 或是現有元素更改大小,則不算做佈局偏移。只有當元素的變更會導致其他可見元素的起始位置發生變化,才叫偏移。
計算公式: 佈局偏移分數 = 影響分數 x 距離分數
影響分數: 前一幀和當前幀的所有不穩定元素的課件區域集合(佔總可視區域的部分)就是當前幀的影響分數。
距離分數: 指的是任何不穩定元素在一幀中位移的最大距離(水平或垂直)除以可視區域的最大尺寸維度(寬度或高度,以較大者為準)。
產生 CLS 的常見原因:
優化方法:
以上五個指標就是目前前端效能指標考量點,以及產生問題原因,優化方法等。每個優化點都可以擴充套件出很多知識以及學習點,所以前端優化這個工作鏈路依然很長;單一點的優化效果可能並不明顯,但五個點全部優化,定然會有質的飛躍。
在實際專案中,優先從前端自身出發,優化完自身後,再去優化協同項。
另外前端優化是一件可持續,並長久的事情,工具技術升級的迭代也會提升專案效能,針對優化這樣的工作一定要持續下去,而不是做一次就OK了。
前端效能優化這條路,道阻且長,行則將至,專研就會有進步,最終定然會成功達到目標。
文章參考: https://web.dev/ https://developer.chrome.com/