用戶端轉譯 HTML 和互動功能

使用 JavaScript 轉譯 HTML 與轉譯伺服器傳送的 HTML 不同,而且可能會影響效能。本課程將說明本指南之間的差異,以及您可以採取哪些措施來維持網站的轉譯成效 (特別是在互動方面)。

根據預設,瀏覽器如果使用瀏覽器內建的瀏覽邏輯 (也稱為「傳統頁面載入」或「硬性瀏覽」),瀏覽器在預設情況下可以精確剖析及呈現 HTML。這類網站有時也稱為多頁面應用程式 (MPA)。

然而,開發人員可能會根據應用程式需求調整瀏覽器預設值。這種情況特別適合使用單頁應用程式 (SPA) 模式的網站,因為這個模式會在用戶端透過 JavaScript 動態建立 HTML/DOM 的大型部分。用戶端轉譯是此設計模式的名稱。如果涉及過多作業,這可能會影響您網站的與下一個繪製模式互動 (INP)

本指南將協助您比較如何使用伺服器傳送至瀏覽器的 HTML,以及使用 JavaScript 在用戶端上建立 HTML 的不同,以及後者如何在關鍵時刻造成高互動延遲。

瀏覽器如何呈現伺服器提供的 HTML

傳統網頁載入作業所使用的瀏覽模式,必須在每次瀏覽時從伺服器接收 HTML。如果你在瀏覽器的網址列中輸入網址,或是點選 MPA 中的連結,則會發生下列一系列事件:

  1. 瀏覽器針對您提供的網址傳送瀏覽要求。
  2. 伺服器會分段使用 HTML 回應。

這些步驟的最後一個步驟是關鍵。它也是伺服器/瀏覽器交換中最基本的效能最佳化機制之一,稱為串流。如果伺服器可以盡快傳送 HTML,且瀏覽器未等待所有回應送達,瀏覽器就可以分區塊處理 HTML。

螢幕截圖顯示伺服器傳送的 HTML 剖析圖,顯示在 Chrome 開發人員工具的效能面板中。由於 HTML 串流格式,
剖析及轉譯伺服器提供的 HTML,如 Chrome 開發人員工具效能面板中的視覺化內容。剖析 HTML 及轉譯所涉及的工作,會分成多個區塊。

就像在瀏覽器中發生的大多數作業一樣,剖析 HTML 會在工作中進行。當 HTML 從伺服器串流到瀏覽器時,瀏覽器會快速對這個 HTML 進行剖析,以區塊的形式傳遞片段。這會導致瀏覽器在處理每個區塊後定期產生主執行緒,避免長時間工作。也就是說,剖析 HTML 時可能發生其他作業,包括向使用者顯示網頁所需的漸進式轉譯工作,以及處理可能在網頁重要啟動期間發生的使用者互動。這種做法代表該網頁的「Interaction to Next Paint (INP)」分數較佳。

值得一提的是從伺服器串流 HTML 時,可以免費進行漸進式剖析和轉譯 HTML,並自動產生至主執行緒,但用戶端算繪作業則無法達成。

瀏覽器如何呈現 JavaScript 所提供的 HTML

每個傳送至網頁的瀏覽要求都需要由伺服器提供一定程度的 HTML,但有些網站會使用 SPA 模式。這種做法通常涉及伺服器提供 HTML 的初始有效負載,但用戶端會從伺服器擷取的資料中組合成網頁的主要內容區域,然後填入網頁的主要內容區域。後續導覽 (在這個情況下也稱為「軟導覽」) 完全由 JavaScript 處理,將新的 HTML 填入網頁。

在更少數情況下,HTML 透過 JavaScript 以動態方式加入 DOM 的極少數情況下,也會發生用戶端算繪等情況。

建立 HTML 或透過 JavaScript 新增至 DOM 有幾種常見方式:

  1. innerHTML 屬性可讓您透過字串設定現有元素的內容,瀏覽器會將該字串剖析為 DOM。
  2. document.createElement 方法可讓您建立新的元素並加入 DOM,而不需使用任何瀏覽器 HTML 剖析功能。
  3. document.write 方法可讓您將 HTML 寫入文件 (然後瀏覽器剖析該方法,就像在方法 #1 一樣)。不過,基於一些原因,我們強烈建議不要使用 document.write
螢幕截圖:剖析透過 JavaScript 轉譯的 HTML 在 Chrome 開發人員工具的效能面板中以視覺化方式呈現。該工作會在封鎖主執行緒的單一長時間工作中執行。
透過 Chrome 開發人員工具的效能面板,透過 JavaScript 在用戶端剖析及呈現 HTML。剖析及轉譯工作涉及的工作不會經過分割,導致長時間的工作封鎖主執行緒。

透過用戶端 JavaScript 建立 HTML/DOM 會產生重大後果:

  • 為回應導覽要求,而由伺服器串流處理的 HTML 工作不同,用戶端上的 JavaScript 工作不會自動分割,因此可能導致長時間的工作封鎖主執行緒。因此,如果您在用戶端建立過多 HTML/DOM,網頁的 INP 可能就會受到負面影響。
  • 如果啟動期間在用戶端上建立了 HTML,瀏覽器預先載入掃描器「無法」找到該 HTML 中參照的資源。這一定會對網頁的最大內容繪製 (LCP) 造成負面影響。雖然這並非執行階段效能問題 (相反地,在擷取重要資源時也會發生網路延遲問題),但您不希望網站的 LCP 受到影響,因為規避這個基本瀏覽器效能最佳化作業。

如何因應用戶端轉譯的效能影響?

如果您的網站非常仰賴用戶端轉譯,但欄位資料中觀察到的 INP 值不佳,您可能會好奇用戶端轉譯功能是否會造成問題。舉例來說,如果您的網站是 SPA,您在欄位資料中可能就會找出導致重大轉譯工作的互動情形。

無論原因為何,您可以嘗試以下這些潛在原因,以順利恢復廣告放送。

盡可能從伺服器提供 HTML 檔案

如前文所述,瀏覽器預設以十分高效能的方式處理來自伺服器的 HTML。這將減少 HTML 的剖析和轉譯作業,可以避免長時間執行的工作,同時大幅改進主執行緒的總時間。這樣可以降低總封鎖時間 (TBT),而待定時間與 INP 密切相關

建立網站時,您可以採用前端架構,如果是的話,請確認您在伺服器上算繪元件的 HTML。這樣會限制網站所需的初始用戶端算繪作業量,且可望改善使用者體驗。

  • 針對 React,建議您使用 Server DOM API 在伺服器上算繪 HTML。不過請注意:傳統的伺服器端算繪方法使用同步方法,因此可能需要較長的首次位元組時間 (TTFB),以及首次顯示內容所需時間 (FCP) 和 LCP 等後續指標。請盡可能使用 Node.js其他 JavaScript 執行階段的串流 API,讓伺服器盡快開始將 HTML 串流至瀏覽器。Next.js 是一個以 React 為基礎的架構,預設提供許多最佳做法。除了在伺服器上自動轉譯 HTML 之外,也可以針對未依使用者情境變更 (例如驗證) 的網頁,以靜態方式產生 HTML。
  • 根據預設,Vue 也會執行用戶端轉譯作業。不過,Vue 就像 React,一樣也可以在伺服器上轉譯元件的 HTML。建議您盡可能利用這些伺服器端 API,或是為 Vue 專案考慮採用更高層級的抽象層,讓實作的最佳做法能夠更輕鬆。
  • 根據預設,系統會在伺服器上轉譯 HTML,不過如果您的元件程式碼需要存取瀏覽器專屬命名空間 (例如 window),您就無法在伺服器上轉譯該元件的 HTML。請盡可能探索替代方法,以免造成不必要的用戶端轉譯。SvelteKit (叫 Svelte 就是 Next.js) 會盡可能在 Svelte 專案中嵌入許多最佳做法,讓單獨使用 Svelte 的專案中避免發生潛在問題。

限制在用戶端建立的 DOM 節點數量

DOM 過大時,顯示這些模組所需的處理時間通常會增加。無論您的網站是完善的 SPA 中心,還是為了進行 MPA 的互動而在現有的 DOM 插入新節點,您都最好盡量縮減這些 DOM。這樣有助於減少用戶端轉譯作業所需的工作量,順利顯示該 HTML,也有助於使網站的 INP 降低。

考慮採用串流服務工作站架構

這項進階技術可能不適用於某些用途,但可將 MPA 轉換成網站,方便使用者在瀏覽某個網頁時立即載入。您可以使用 Service Worker,在 CacheStorage 中預先快取網站的靜態部分,同時使用 ReadableStream API 從伺服器擷取網頁的其他 HTML。

成功使用這項技術時,並不會在用戶端上建立 HTML,但如果從快取中即時載入部分內容,可確保網站載入速度快。採用這種做法的網站有幾乎像是 SPA,但不會發生用戶端轉譯問題。還能減少從伺服器請求的 HTML 量

簡單來說,串流服務工作站架構不會「取代」瀏覽器的內建導覽邏輯,而是「新增」該架構。如要進一步瞭解如何利用 Workbox 達成這個目標,請參閱「加快多頁面應用程式如何使用串流功能」。

結語

網站接收及顯示 HTML 的方式會影響效能。當您仰賴伺服器傳送網站運作所需的全部 (或大量) 的 HTML 時,可以獲得大量免費:漸進式剖析和轉譯,以及自動載入主執行緒,避免長時間工作。

用戶端 HTML 轉譯功能帶來的一些潛在效能問題,在多數情況下都能避免。不過,基於每個網站的規定,您無法 100% 都無法完全避免這種情況。為了減輕用戶端網站過度轉譯可能會導致長時間工作,請務必盡可能從伺服器傳送大量網站的 HTML、盡可能縮小必須顯示在用戶端的 HTML 上的 DOM 大小,並考慮採用其他架構,以加快 HTML 向用戶端的放送速度,同時利用從伺服器載入的 HTML 來呈現瀏覽器提供的漸進式剖析與轉譯方法。

如果可以盡量縮短網站的用戶端算繪資料,那麼除了網站的 INP,您也會改善其他指標,例如 LCP、TBT,有時甚至 TTFB 等。

主頁橫幅由 Maik JonietzUnsplash 提供。