前言
頁面的性能優化對于前端來說永遠是離不開的課題,前端性能優化一直也不是作為一個單獨的問題存在,它往往需要開發者結合計算機網絡、瀏覽器相關技術、前端框架、構建工具以及開發者自己的代碼等多層面去思考優化的方案,所以前端性能不應該是前端領域的一個孤島??,而需要作為串聯起前端技術的零件。
如何去進行性能優化?
一說到前端性能優化,可能大家一開始的想法就是壓縮頁面產物大小、圖片換成雪碧圖、資源懶加載等一系列方式,但是要知道性能優化并不是直接套用方法論的,性能優化的前提清楚需要頁面需要優化的指標,并根據有方向有目的進行優化。
確立優化的指標
古早時期,大家常常會把性能優化與頁面白屏時間劃上等號,但是白屏時間短并不代表頁面性能就好,例如頁面進去是渲染的是loading動畫又或者是一個可有可無的模塊,雖然白屏時間是短了,可以渲染出來的內容對用戶來說是毫無意義的,美其名曰提升了首屏性能,實際上不過是掩耳盜鈴罷了。
對大多數頁面來說,性能優化的的宗旨還是確保用戶可以盡快的看到有用的頁面信息,那頁面加載到什么程度才能夠算是渲染出有用的頁面信息呢?
FMP(first print)即首次有意義的渲染,這個指標感覺真的和我們所說的有用的頁面信息是完美契合。
我們可以看到在FMP的階段,頁面中大部分元素其實都被渲染出來,我們來看看這個值到底是怎么被計算的。
image.png
在頁面渲染和解析的過程中,布局對象會被逐步添加至布局樹中,從上圖可以看出布局對象的數量和頁面完成度是高度相關的,所以業界比較認可的計算方式是頁面在加載和渲染過程中最大布局變動之后的繪制時間作為當前頁面的FMP,上圖對應的FMP的值為1.907s。
通常的檢測手段是使用監聽頁面整體的DOM變化,然后通過計算變化比例,找到DOM變化幅度占比最高的時間點。
FMP需要瀏覽器支持 API,并且FMP的計算過程是十分復雜的。在我們團隊開發的時候會比較hack,頁面直接上報的是首屏接口被處理后React 后的時間或者是首屏大圖渲染的時間,而其實這個時間并非是頁面精準的FMP值。
在 6.0的性能規范中,廢棄了FMP的這個指標。官方給到的解釋主要有兩點:
LCP
相比于 FMP 計量的復雜和不確定性,W3C性能小組和Google研究發現,衡量頁面主要內容加載更準確方法是查看最大元素的呈現時間。也就是的指標 LCP 。
LCP(Largest Paint) 指的是視口中可見最大圖片或文本塊的渲染出來的時間。所謂的最大圖片或文本塊包含以下內容:
元素、 元素中的 元素。
元素的第一幀圖片。
使用url()加載的背景圖片。
包含文本節點和其他嵌套文本的塊級元素。
如何優化LCP指標
由于LCP相關的優化涉及的內容比較多,可以翻閱我的另一篇文章LCP優化的最佳實踐[1]。
但是一個真正用戶體驗好的頁面并不僅僅只是頁面LCP數值好就代表真的體驗好,根據最新Google最新的頁面性能的核心指標標準顯示,除了LCP外,還包括互動響應指標 INP( to Next Paint) 以及布局偏移指標 CLS( Layout Shift) ,這三個指標共同組成了頁面核心性能指標。
image.pngINP( to Next Paint)
INP( to Next Paint)是使用 Event Timing API 中的數據來評估網頁響應能力。INP 會在網頁生命周期內觀察用戶與網頁進行的所有點擊、點按和鍵盤互動的延遲時間,并報告最長持續時間。
INP大家可能會感受到陌生,可能更熟悉的指標是FID(First Input Paint),FID用戶首次與頁面交互(例如點擊鏈接、按鈕等)到瀏覽器實際能夠開始處理事件處理器之間的時間。2年前這個指標還是檢測頁面交互性的核心指標,如今將被INP取代了。
INP和FID的區別
INP 會統計網頁生命周期內觀察用戶與網頁進行的所有點擊、點按和鍵盤互動的延遲時間。而FID僅測量了頁面上首次互動的輸入延遲,所以我認為可以等價理解為FID像是成為了INP的子集。
對于純渲染的頁面來說,其實INP記錄的交互時間的最大值可能就是FID,因為此時大量的JS執行,以及DOM生成,以及樣式渲染,此時主線程肯定會被長時間占用的。所以對于純渲染的頁面可能考慮首屏的INP指標。但是對于一些有復雜交互的頁面,例如文本編輯器或聯動效果的的表單頁面,可能首屏內容渲染是很快的,但是可能后續的互動時間會比較耗時,所以此時FID是不能衡量互動性能的,此時INP更能體現頁面的交互性能。
INP指標怎么計算的?
首先INP指標的總耗時主要包括三個方面:
輸入延遲,從用戶發起與網頁的互動開始,在互動的事件回調開始運行時結束。
JS處理時間回調的耗時。
互動效果在瀏覽器下一幀呈現效果的時間。這三個階段組成了INP統計的互動耗時,若INP小于200ms,頁面的互動性能可以被認為很好。
如何優化INP的指標
減少非首屏的JS資源的加載和執行,減少JS對主線程的占用時間,提升首屏響應速度。
優化互動事件的回調,盡可能讓出頁面的主線程,優先完成優先級高的任務回調。
這里可以借用web.dev網站提供的一個案例[2]了解下如何在日常開發中讓主線程,拆分掉冗長的事件回調。
避免強制同步布局和布局抖動。
同步布局: 強制同步布局是指在執行 或者 CSS 動畫過程中,代碼強制瀏覽器進行布局計算(Reflow),然后再讀取某些樣式信息。例如,如果一個 函數對 DOM 進行修改后立即讀取某些樣式屬性(如元素的偏移量或尺寸),瀏覽器必須先完成布局計算,以確保返回的信息是最新的。這種強制的布局過程可能會導致顯著的性能瓶頸,因為它阻塞了主線程,直到布局計算完成。
布局抖動: 布局抖動通常是由于代碼在一次事件循環中多次讀寫 DOM 屬性而導致的連續布局計算。每次讀取或寫入都可能導致布局的重新計算,如果這些操作在循環或頻繁的函數調用中進行,就會導致大量的計算開銷,從而降低頁面性能。
盡可能減少DOM的數量和深度,降低DOM重新渲染所造成的性能影響。
CLS
CLS( Layout Shift)是用于衡量視覺穩定性的重要指標,它有助于量化用戶遇到意外布局偏移的頻率。
CLS是如何計算的?
首先我們看看CLS的計算公式:
CLS值?=?偏移比例(偏移的距離占視窗的距離的比例)*?元素比例(元素高度占視窗的高度的比例)
接著我們根據一個具體案例了解下CLS的計算過程:
(1) 起初頁面加載出了粉色的一個div塊。
(2)之后黃色模塊再加載出來。
這是后線出案的樓塊.png
我們假定粉色模塊的高度占視窗的50% ,所以元素比例為0.5,然后假定黃色模塊占視窗的20% ,其造成的偏移距離也是20% ,所以偏移比例為0.2。最終CLS的值等于0.5 * 0.2 = 0.1。CLS低于0.1可以代表視覺穩定性比較好。
被誤解的CLS統計
不知道會不會有些人和我一樣有這樣的困惑。我的頁面可能有以下場景,例如點擊展開,又或者是搜索框展示提醒之類的,用戶的一些交互輸入導致頁面偏移,這些情況導致的偏移都會被統計到CLS中去么?
于是我迅速的翻閱了下 web.dev[3] 的相關文檔,文檔是這么闡述的,對于在用戶輸入后 500 毫秒內發生的布局偏移,系統會設置 標志,因此這段時間發生的偏移會從計算中排除。
因為這些用戶主動去進行的輸入,說明用戶是對偏移有預期的,但是例如頁面加載的時候,資源加載緩慢導致的偏移,這種才會被理解為意料之外的偏移,最終被統計到CLS的指標中去。
如何優化CLS指標
(1) 預設高寬的圖片或者是前端模塊組件。這些圖片或者組件可能依賴的網絡請求所以存在延時,在數據到達時導致頁面偏移。
(2) CSS動畫盡量使用和 僅影響合成階段的屬性。如果直接操作元素的 top 或 left等屬性,會觸發頁面的重新布局、繪制和合成。所以需要修改元素的位置可以使用,而修改大小可以使用,這兩個屬性只會影響合成階段,不會影響布局階段。
(3) 預加載的字體資源。加載字體資源由于也需要網絡請求,所以在字體資源加載生效之后,導致頁面的內容偏移。而且字體比較特殊,需要在頁面上使用時才會加載,所以為了盡快使用上字體文件,可以使用preload預加載資源。
結語
其實性能優化是一個十分需要耐心的工作,我們需要根據各種指標了解到我們頁面的不足之處,然后再圍繞具體指標的優化策略去對癥下藥,而不是看到網上有什么優化策略,就依葫蘆畫瓢。因為每個項目的場景,優化訴求都不同,例如toC的H5頁面可能追求更好的LCP指標和CLS指標,而toB的CMS應用追求更好的INP指標。
個人覺得性能指標應該是作為我們作為性能優化的導向,讓我們有性能優化的方向,而不是衡量頁面性能的絕對標準。有時候不同機型、不同網絡情況優化的效果可能也不同,所以我們也不用過度的追求的最終得分。
所以前端到底要怎么去優化性能?我認為結合自己項目的實際情況,按照相應的指標對癥下藥去優化就好了。
最后
Node 社群
我組建了一個氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學習感興趣的話(后續有計劃也可以),我們可以一起進行Node.js相關的交流、學習、共建。下方加 考拉 好友回復「Node」即可。
???“分享、點贊、在看” 支持一下
*請認真填寫需求信息,我們會在24小時內與您取得聯系。