JavaScript 啟動最佳化

當我們建構的網站越來越依賴 JavaScript 時,有時會以我們不一定能輕易察覺的方式,為我們傳送的內容付出代價。本文將說明,如果想讓網站在行動裝置上快速載入並提供互動功能,為什麼需要自律。傳送較少的 JavaScript,代表網路傳輸時間、解壓縮程式碼的時間,以及剖析和編譯 JavaScript 的時間都會減少。

網路

大多數開發人員在考量 JavaScript 的成本時,都會從下載和執行成本的角度思考。使用者的連線速度越慢,透過網路傳送更多位元組的 JavaScript 所需的時間就越長。

瀏覽器要求資源時,必須先擷取資源,然後解壓縮。如果是 JavaScript 等資源,則必須先剖析及編譯,才能執行。

這可能會造成問題,因為使用者實際的網路連線類型可能並非 3G、4G 或 Wi-Fi。您可以使用咖啡店的 Wi-Fi,但連線至 2G 速度的行動熱點。

您可以透過下列方式降低 JavaScript 的網路傳輸成本:

  • 只傳送使用者需要的程式碼。
  • 壓縮
  • 壓縮
    • 至少使用 gzip 壓縮文字資源。
    • 建議使用 Brotli ~q11。Brotli 的壓縮率優於 gzip。這項功能協助 CertSimple 節省了 17% 的壓縮 JS 位元組大小,並協助 LinkedIn 節省了 4% 的載入時間。
  • 移除未使用的程式碼。
  • 快取程式碼,盡可能減少網路傳輸。
    • 使用 HTTP 快取,確保瀏覽器有效快取回應。決定指令碼的最佳生命週期 (max-age),並提供驗證符記 (ETag),避免傳輸未變更的位元組。
    • Service Worker 快取可提升應用程式的網路彈性,並讓您能積極存取 V8 的程式碼快取等功能。
    • 使用長期快取,避免重新擷取未變更的資源。如果使用 Webpack,請參閱檔案名稱雜湊。

剖析/編譯

下載後,JavaScript 的最重成本之一,就是 JS 引擎剖析/編譯這段程式碼的時間。在 Chrome 開發人員工具中,剖析和編譯是「Performance」面板中黃色「Scripting」時間的一部分。

ALT_TEXT_HERE

「Bottom-Up」和「Call Tree」分頁會顯示確切的剖析/編譯時間:

ALT_TEXT_HERE
Chrome 開發人員工具的「Performance」(效能) 面板 >「Bottom-Up」(由下而上)。啟用 V8 的執行階段呼叫統計資料後,我們就能查看剖析和編譯等階段所花費的時間

但這為何如此重要?

ALT_TEXT_HERE

如果剖析/編譯程式碼的時間過長,使用者可能需要等待很久才能與網站互動。傳送的 JavaScript 越多,網站互動前剖析和編譯所需的時間就越長。

「以位元組為單位,瀏覽器處理 JavaScript 的成本高於處理相同大小的圖片或網頁字型」- Tom Dale

與 JavaScript 相比,處理相同大小的圖片會產生許多成本 (仍須解碼!),但在一般行動硬體上,JS 更有可能對網頁的互動性造成負面影響。

ALT_TEXT_HERE
JavaScript 和圖片位元組的成本差異很大。圖片在解碼和光柵化時,通常不會阻斷主執行緒,也不會妨礙介面互動。不過,JS 可能會因為剖析、編譯和執行成本而延遲互動。

當我們說剖析和編譯速度緩慢時,背景資訊很重要,我們在這裡討論的是平均手機。一般使用者的手機可能配備速度緩慢的 CPU 和 GPU、沒有 L2/L3 快取,甚至可能記憶體受限。

網路功能和裝置功能不一定相符。即使使用者擁有出色的 Fiber 連線,也不一定有最好的 CPU 來剖析及評估傳送至裝置的 JavaScript。反之亦然,如果網路連線不佳,但 CPU 速度極快,— Kristofer Baxter,LinkedIn

下方顯示在低階和高階硬體上剖析約 1 MB 解壓縮 (簡單) JavaScript 的成本。市面上最快的手機和一般手機在剖析/編譯程式碼的時間上,有 2 到 5 倍的差異。

ALT_TEXT_HERE
這張圖表顯示 1 MB JavaScript 組合 (約 250 KB gzip 壓縮) 在不同等級的電腦和行動裝置上的剖析時間。評估剖析成本時,應考量解壓縮後的數據,例如 ~250 KB 的 gzip 壓縮 JS 解壓縮後會變成 ~1 MB 的程式碼。

如果是實際網站,例如 CNN.com 呢?

在 iPhone 8 這類高階手機上,剖析/編譯 CNN 的 JS 只要約 4 秒,而一般手機 (Moto G4) 則需要約 13 秒。這可能會大幅影響使用者與網站完整互動的速度。

ALT_TEXT_HERE
上圖比較了 Apple A11 Bionic 晶片與 Snapdragon 617 在一般 Android 硬體上的剖析時間。

這凸顯了在「平均」硬體 (例如 Moto G4) 上進行測試的重要性,而不只是在您可能擁有的手機上進行測試。不過,情境很重要:請根據使用者的裝置和網路條件進行最佳化。

ALT_TEXT_HERE
Google Analytics 可提供洞察資料,協助您瞭解實際使用者存取網站時使用的行動裝置類別。這有助於瞭解他們在運作時面臨的實際 CPU/GPU 限制。

我們真的傳送了太多 JavaScript 嗎?呃,可能吧 :)

我們使用 HTTP Archive (前 50 萬個網站) 分析行動裝置上的 JavaScript 狀態,發現 50% 的網站需要超過 14 秒才能互動。這些網站最多會花 4 秒剖析及編譯 JS。

ALT_TEXT_HERE

如果考量到擷取及處理 JS 和其他資源所需的時間,使用者可能需要等待一段時間,才會覺得網頁已準備就緒,這或許並不令人意外。我們絕對可以做得更好。

從網頁中移除不重要的 JavaScript,可縮短傳輸時間、減少 CPU 密集剖析和編譯作業,以及潛在的記憶體負擔。這也有助於加快網頁互動速度。

執行時間

不只是剖析和編譯會產生費用,JavaScript 執行 (剖析/編譯後執行程式碼) 是必須在主執行緒上執行的作業之一。執行時間過長也會延遲使用者與網站互動的時間。

ALT_TEXT_HERE

如果指令碼執行時間超過 50 毫秒,Time to Interactive 就會延遲,延遲時間等於下載、編譯和執行 JS 的全部時間。 - Alex Russell

為解決這個問題,JavaScript 適合分成小區塊,避免鎖定主執行緒。看看是否能減少執行期間的工作量。

其他費用

JavaScript 也可能透過其他方式影響網頁效能:

  • 記憶體。網頁可能會因 GC (垃圾收集) 而頻繁卡頓或暫停。瀏覽器回收記憶體時,JS 執行作業會暫停,因此頻繁收集垃圾的瀏覽器可能會比我們預期的更常暫停執行。避免記憶體流失和頻繁的 GC 暫停,確保網頁不會卡頓。
  • 在執行階段,長時間執行的 JavaScript 可能會封鎖主執行緒,導致網頁沒有回應。將工作拆分為較小的部分 (使用 requestAnimationFrame() 或 requestIdleCallback() 進行排程),可盡量減少回應速度問題,有助於改善 Interaction to Next Paint (INP)。

降低 JavaScript 傳送成本的模式

如要縮短 JavaScript 的剖析/編譯和網路傳輸時間,可以採用一些模式,例如以路徑為基礎的分塊或 PRPL。

PRPL

PRPL (推送、算繪、預先快取、延遲載入) 是一種模式,可透過積極的程式碼分割和快取,最佳化互動性:

ALT_TEXT_HERE

我們來看看這項功能的效果。

我們使用 V8 的執行階段呼叫統計資料,分析熱門行動網站和漸進式網頁應用程式的載入時間。如圖所示,剖析時間 (以橘色表示) 占了這些網站的大部分時間:

ALT_TEXT_HERE

Wego 網站使用 PRPL,成功縮短路徑剖析時間,快速提供互動功能。上述許多其他網站都採用程式碼分割和效能預算,試圖降低 JS 成本。

漸進式啟動

許多網站為了提高內容可見度,不惜犧牲互動性。如要在 JavaScript 套件較大時快速完成首次繪製,開發人員有時會採用伺服器端轉譯,然後在最終擷取 JavaScript 時「升級」以附加事件處理常式。

請注意,這項操作會產生費用。1) 您通常會傳送「較大」的 HTML 回應,這可能會延遲互動性;2) 使用者可能會處於詭異的狀態,在 JavaScript 處理完成之前,有一半的體驗實際上無法互動。

漸進式啟動可能是更好的方法。傳送功能最少的網頁 (僅由目前路徑所需的 HTML/JS/CSS 組成)。隨著更多資源抵達,應用程式可以延遲載入並解鎖更多功能。

ALT_TEXT_HERE
Progressive Bootstrapping by Paul Lewis

根據檢視畫面中的內容載入程式碼,是最佳做法。PRPL 和漸進式啟動模式可協助達成這個目標。

結論

傳輸大小對低階網路至關重要。剖析時間對 CPU 繫結裝置來說很重要。因此,請務必降低這些指標。

許多團隊都成功採用嚴格的效能預算,降低 JavaScript 傳輸和剖析/編譯時間。請參閱 Alex Russell 的「Can You Afford It?: Real-world Web Performance Budgets」(實際網頁效能預算),瞭解行動裝置預算指南。

ALT_TEXT_HERE
建議您考量架構決策能為應用程式邏輯保留多少 JS「空間」。

如果您要建構針對行動裝置的網站,請盡可能在代表性硬體上開發,保持 JavaScript 剖析/編譯時間低,並採用效能預算,確保團隊能夠監控 JavaScript 成本。

瞭解詳情