從解析HTML開始,破解頁面渲染時間長難題
摘要:在本文中,將重點關注網頁的初始渲染,即它從解析 HTML 開始。 我將探索可能導致高渲染時間的問題,以及如何解決它們。
本文分享自華為雲社區《頁面首屏渲染性能指南》,作者:Ocean2022。
我們知道渲染頁面是一個將服務器的響應內容翻譯成圖片的過程。但是,如果你頁面的渲染性能比較糟糕的話,可能會帶來相對較高的跳出率。
在本文中,我將重點關注網頁的初始渲染,即它從解析 HTML 開始。 我將探索可能導致高渲染時間的問題,以及如何解決它們。
關鍵渲染路徑(CRP)
關鍵渲染路徑 (CRP) 是瀏覽器將代碼轉換為屏幕上可顯示像素的過程。 它有幾個階段,其中一些可以並行執行以節省時間,但有些部分必須依次完成。 如下圖所示:
首先,一旦瀏覽器得到響應,它就會開始解析它。 當它遇到依賴項時,它會嘗試下載它。 如果它是一個樣式表文件,瀏覽器必須在渲染頁面之前完全解析它,這就是為什麼 CSS 會阻塞渲染的原因。
如果是腳本,瀏覽器必須:停止解析,下載腳本,然後運行。 只有在那之後它才能繼續解析,因為 JavaScript 程序可以改變網頁的內容(尤其是 HTML)。 這就是為什麼 JS 會阻塞解析的原因。
完成所有解析後,瀏覽器將構建文檔對象模型 (DOM) 和級聯樣式表對象模型 (CSSOM)。 將它們組合在一起得到渲染樹。 頁面的不顯示部分不會進入渲染樹,因為它只包含繪製頁面所需的數據。
倒數第二步是將渲染樹進行布局, 這個階段也稱為迴流:就是計算每個渲染樹節點的每個位置及其大小的地方。
最後一步是繪製。 它會根據瀏覽器在前一階段計算得到的數據對像素進行着色。
優化相關結論
因此,根據這一過程,我們在優化性能方面,得出了一些結論。如果你要提升頁面初始化渲染的性能,你需要:
- 減少傳輸的數據量
- 減少瀏覽器必須下載的資源數量(尤其是阻塞的資源)
- 減小 CRP 的長度
同時,我們會根據下面 3 個指標來衡量優化的效率:
- FP(First Paint)
- FCP(First Contentful Paint)
- FMP(First Meaningful Paint)
除了渲染時間之外,還有其他一些因素也需要考慮。例如,你的頁面使用了多少阻塞資源以及下載它們需要多長時間。
性能優化策略
鑒於我們在上面得出的結論,我們得出網站性能優化有三種主要策略:
- 盡量減少通過網絡傳輸的數據量;
- 減少通過網絡傳輸的資源總數;
- 縮短關鍵渲染路徑;
1. 減少要傳輸的數據量
首先,移除所有未使用的部分,例如 JavaScript 中無法訪問的函數、帶有從不匹配任何元素的選擇器的樣式以及被 CSS 永遠隱藏的 HTML 標籤。 其次,刪除所有重複項。
然後,我建議建立一個自動壓縮過程。 例如,它應該從你的後端服務中刪除所有注釋(但不是源代碼)以及每個不包含附加信息的字符(例如 JS 中的空白字符)。
完成後,我們剩下的可以是文本字符串。 這意味着我們可以安全地應用諸如 GZIP(大多數瀏覽器都理解)之類的壓縮算法。
最後,還有緩存。 瀏覽器第一次呈現頁面時它不會有幫助,但它會在以後的訪問中節省很多。 但是,記住兩點至關重要:
- 如果你使用 CDN,請確保支持緩存並在正確設置。
- 與其等待資源的到期,不如 將文件的「指紋」嵌入到其 URL 中,以使本地緩存無效。
當然,應該為每個資源定義緩存策略。 有些可能很少改變或根本不會改變,有的則是變化的很快,還有些文件包含敏感的信息(可以使用 「private」 防止 CDN 緩存私有數據)。
2. 減少關鍵資源的總數
「關鍵」僅指網頁正確呈現所需的資源。 因此,我們可以直接跳過所有流程中沒有涉及的樣式以及腳本文件。
樣式
為了告訴瀏覽器不需要特定的 CSS 文件,我們應該為所有引用樣式表的鏈接設置媒體屬性。 使用這種方法,瀏覽器將只根據需要處理與當前媒體(設備類型、屏幕尺寸)匹配的資源,同時降低所有其他樣式表的優先級。 例如,如果你將 media=「print」 屬性添加到引用樣式以打印頁面的樣式標記,則這些樣式不會在不打印媒體時干擾你的關鍵渲染路徑。
為了進一步改進該過程,你還可以將一些樣式內聯,這可以為我們節省了至少一次到服務器的往返行程。
腳本
如上所述,腳本會阻塞解析,因為它們可以改變 DOM 和 CSSOM。 為了避免這一點,所有腳本標籤都必須用屬性標記——異步或延遲。
標有 async 的腳本不會阻塞 DOM 構建或 CSSOM,因為它們可以在 CSSOM 構建之前執行。 但請記住,內聯腳本無論如何都會阻止 CSSOM,除非你將它們放在 CSS 之上。相比之下,標有 defer 的腳本將在頁面加載結束時進行執行。
換句話說,使用 defer,腳本直到頁面加載事件被觸發後才會執行,而 async 讓腳本在文檔被解析時就會在後台運行。
3.縮短關鍵渲染路徑長度
最後,應將 CRP 長度縮短到可能的最小值。
作為樣式標籤屬性的媒體查詢將減少必須下載的資源總數。 script 標籤屬性 defer 和 async 將防止相應的腳本阻塞解析。
使用 GZIP 壓縮、壓縮和歸檔資源將減少傳輸數據的大小(從而也減少數據傳輸時間)。
內聯一些樣式和腳本也可以減少瀏覽器和服務器之間的往返次數。
按照最新的最佳性能實踐理念,一個網站應該做的最快的第一件事就是展示 ATF 內容。 ATF 代表首屏。 這是立即可見的區域,無需滾動。 因此,最好以首先加載所需樣式和腳本的方式重新排列與渲染相關的所有內容,而其他所有內容都停止(既不解析也不渲染)。
結尾
總而言之,網站性能優化包含了網站響應的各個方面,例如緩存、設置 CDN、重構、資源優化等,但是所有這些都可以逐步完成。 作為 Web 開發人員,你可以將本文作為參考,並始終記住在實驗之前和之後測量性能。
瀏覽器開發人員盡最大努力優化你訪問的每個頁面的網站性能,這就是瀏覽器通常實現所謂的「預加載器」的原因。 這部分程序會在你以 HTML 格式請求的資源之前進行掃描,以便一次發出多個請求並讓它們並行運行。 這就是為什麼在 HTML(逐行)以及腳本標籤中保持樣式標籤彼此靠近的原因。
此外,嘗試批量更新 HTML 以避免多個布局事件,這些事件不僅由 DOM 或 CSSOM 中的更改觸發,而且在設備方向更改和窗口大小調整時也會觸發。