用戶端轉譯 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 串流時,程式碼的區塊會在多個較短的工作中進行處理,且轉譯階段會逐漸增加。
在 Chrome 開發人員工具的效能面板中,以視覺化方式呈現伺服器提供的 HTML 程式碼剖析與轉譯。剖析 HTML 及轉譯這些工作會分為多個區塊。

就像瀏覽器中發生的大部分作業一樣,剖析 HTML 也是在工作內進行。當 HTML 從伺服器串流至瀏覽器時,瀏覽器會在串流的片段中分段抵達時,立即執行此 HTML 的剖析。這會導致瀏覽器在處理每個區塊後,定期產生主執行緒,以避免長時間的工作。這表示在剖析 HTML 時,也可能會發生其他工作,包括向使用者顯示網頁所需的漸進式轉譯工作,以及處理網頁重要啟動期間可能發生的使用者互動。這個方法可提升網頁的與下一個繪製動作互動 (INP) 分數,

重點在於從伺服器串流 HTML 時,您可以漸進地剖析及轉譯 HTML,並且免費自動產生到主執行緒。而用戶端算繪功能則不會有這些差異。

瀏覽器如何轉譯 JavaScript 提供的 HTML

雖然每次向網頁提出瀏覽要求時,都必須由伺服器提供一定的 HTML 程式碼,但有些網站會使用 SPA 模式。這種方法通常涉及伺服器提供的 HTML 的最小初始承載,但是用戶端會從伺服器擷取的資料擷取出 HTML 組合,填入網頁的主要內容區域。後續瀏覽 — 有時也稱為「軟導覽」在本例中 - 完全由 JavaScript 處理,在網頁中填入新的 HTML。

在少數情況下,非 SPA 也可能會發生用戶端轉譯作業,因為 HTML 是透過 JavaScript 動態加入 DOM。

以下列舉幾種透過 JavaScript 建立 HTML 或新增至 DOM 的常見方式:

  1. innerHTML 屬性可讓您透過字串設定現有元素的內容,而瀏覽器會將其剖析為 DOM。
  2. document.createElement 方法可讓您在不使用任何瀏覽器 HTML 剖析的情況下,新建要加入 DOM 的新元素。
  3. document.write 方法可讓您將 HTML 寫入文件中 (而且瀏覽器會剖析 HTML 方法,做法與方法 #1 相同)。不過,基於許多原因,我們強烈建議不要使用 document.write
在 Chrome 開發人員工具的「效能」面板中,以視覺化方式呈現透過 JavaScript 轉譯 HTML 程式碼的螢幕截圖。工作會在封鎖主執行緒的單一長時間工作中執行。
在 Chrome 開發人員工具的「效能」面板中,以圖表呈現在用戶端透過 JavaScript 剖析及轉譯 HTML。剖析及轉譯相關工作不會分段,導致會封鎖主執行緒的長時間工作。

透過用戶端 JavaScript 建立 HTML/DOM 可能會造成重大後果:

  • 有別於伺服器為了回應導覽要求而串流的 HTML,用戶端上的 JavaScript 工作不會自動分塊,這可能導致長時間的工作阻斷主執行緒。也就是說,如果您在用戶端上一次建立過多 HTML/DOM,網頁的 INP 可能會受到負面影響。
  • 如果在啟動期間在用戶端上建立 HTML,瀏覽器預先載入掃描器不會找到其內參照的資源。這絕對會對網頁的最大內容繪製 (LCP) 造成負面影響。這並非執行階段效能問題 (而是擷取重要資源時會發生網路延遲的問題),但您不希望因為這項基本的瀏覽器效能最佳化措施,而影響您網站的 LCP。

因應用戶端轉譯技術的效能影響

如果您的網站明顯仰賴用戶端轉譯,而欄位資料中的 INP 值不佳,您可能會想瞭解用戶端轉譯功能是否與問題有關。例如,如果您的網站是 SPA,您的欄位資料可能會顯示促成大量算繪工作的互動。

無論原因為何,你都可以探索以下可能原因,讓自己的解決方法恢復正常。

盡可能從伺服器提供 HTML

如前所述,瀏覽器預設會以效果極佳的方式處理來自伺服器的 HTML。它會以避開長時間工作的方式,中斷 HTML 的剖析和轉譯,並最佳化主執行緒的總作業時間。這樣會降低總封鎖時間 (TBT),且 TBT 與 INP 高度相關

您可能仰賴前端架構來建立網站。如果是的話,請確認你會在伺服器上呈現元件 HTML。這樣會限制網站所需的初始用戶端轉譯作業量,有助於提升體驗。

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

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

DOM 較大時,轉譯這些 DOM 所需的處理作業往往會增加。無論您的網站是發展成熟的 SPA,還是因為 MPA 互動結果而在現有的 DOM 插入新節點,都建議您盡量減少這些 DOM。這有助於減少用戶端轉譯期間轉譯該 HTML 作業所需的工作,或許有助於維持網站的 INP 較低位置。

考慮串流 Service Worker 架構

這是一種進階的技術,不見得適用於所有使用情境,但可將您的 MPA 轉換成網站,讓使用者在瀏覽到下個網頁時,感覺就像是在載入後立即載入的網站。您可以使用 Service Worker,在使用 ReadableStream API 從伺服器擷取網頁 HTML 的其他部分,同時在 CacheStorage 中預先快取網站的靜態部分。

如果成功使用這項技巧,您便無法在用戶端建立 HTML,但若能立即從快取中載入部分內容,將會給網站快速載入的機會。採用這種方法的網站看起來幾乎就像 SPA 一樣,但會降低用戶端轉譯的難度。這樣也會減少您向伺服器要求的 HTML 數量

簡單來說,串流 Service Worker 架構不會「取代」瀏覽器的內建導覽邏輯,而是「新增」瀏覽器。如要進一步瞭解如何透過 Workbox 達到這項作業,請參閱「運用串流加快多頁面應用程式速度」。

結論

網站接收及轉譯 HTML 如何影響效能。當您使用伺服器傳送網站所需的全部 (或大部分) HTML 程式碼時,就不用擔心受限於多餘的剖析和轉譯作業,還可以自動產生主執行緒來避免長時間的工作。

用戶端 HTML 轉譯功能造成許多潛在的效能問題,在許多情況下都能避免。然而,考量到個別網站的規定,並非在所有情況下都無法完全避免。為了避免因用戶端網站轉譯過多而造成潛在的長時間工作,請務必盡可能從伺服器傳送網站 HTML、盡可能減少 DOM 大小,讓必須在用戶端顯示的 HTML 盡可能縮小,並考慮其他架構,以加快將 HTML 傳送至用戶端的速度,同時善用瀏覽器為從伺服器載入的 HTML 所提供的漸進式剖析功能。

盡可能減少網站的用戶端轉譯內容,不僅能改善網站的 INP,也能改善 LCP、TBT 等指標,在某些情況下甚至還可提高 TTFB。

主頁橫幅由 Maik Jonietz 提供。