由於我們建構的網站更仰賴 JavaScript,有時我們會以難以輕易察覺的方式傳送資料,並為此付費。本文將說明為何只要稍微自律,就能讓網站在行動裝置上快速載入並提供互動功能。提供的 JavaScript 越少,網路傳輸時間就越短,解壓縮程式碼所花的時間就越少,剖析及編譯 JavaScript 的時間也越短。
網路
大多數開發人員在考量 JavaScript 成本時,會以下載和執行成本為依據。使用者連線速度越慢,透過網路傳送的 JavaScript 位元組數量越多,所需時間就會越長。
這可能會造成問題,因為使用者的有效網路連線類型可能並非 3G、4G 或 Wi-Fi。你可以使用咖啡廳的 Wi-Fi,但連線速度會降至 2G。
您可以透過以下方式降低 JavaScript 的網路傳輸成本:
- 只傳送使用者需要的驗證碼。
- 壓縮
- 使用 UglifyJS 壓縮 ES5 程式碼。
- 使用 babel-minify 或 uglify-es 壓縮 ES2015 以上版本的程式碼。
- 壓縮
- 移除未使用的程式碼。
- 使用開發人員工具程式碼涵蓋率,找出可移除或延後載入的程式碼。
- 請使用 babel-preset-env 和 browserlist,避免轉譯新式瀏覽器中已存在的功能。進階開發人員可能會發現,仔細分析 webpack 套件有助於找出可裁減不必要依附元件的機會。
- 如要去除程式碼,請參閱樹狀結構搖晃、Closure 編譯器的進階最佳化功能,以及用於 Moment.js 等程式庫的 lodash-babel-plugin 或 webpack 的 ContextReplacementPlugin 等程式庫修剪外掛程式。
- 快取程式碼,盡量減少網路往返次數。
剖析/編譯
下載完成後,JavaScript 的最大成本之一,就是 JS 引擎解析/編譯此程式碼所需的時間。在 Chrome 開發人員工具中,剖析和編譯是「效能」面板中黃色「指令碼」時間的一部分。
「Bottom-Up」和「Call Tree」分頁會顯示確切的剖析/編譯時間:

但這點為何重要?
花費大量時間剖析/編譯程式碼,可能會大幅延遲使用者與網站互動的時間。您傳送的 JavaScript 越多,網站互動性建立前,解析及編譯所需的時間就會越長。
以位元組為單位來說,瀏覽器處理 JavaScript 的成本高於處理同等大小的圖片或網路字型 — Tom Dale
與 JavaScript 相比,處理同等大小的圖片需要耗費大量成本 (仍須解碼),但在一般行動裝置硬體上,JS 更有可能對網頁互動性造成負面影響。

當我們談到剖析和編譯速度緩慢時,背景資訊就很重要,因為我們指的是一般的手機。一般使用者的手機可能搭載速度較慢的 CPU 和 GPU、沒有 L2/L3 快取,甚至可能有記憶體限制。
網路功能和裝置功能不一定相符。使用者即使擁有絕佳的光纖連線,也不一定擁有最佳 CPU 來剖析及評估傳送至裝置的 JavaScript。反之亦然,如果網路連線品質不佳,但 CPU 速度極快,— LinkedIn 的 Kristofer Baxter
下方是低階和高階硬體在剖析約 1 MB 的解壓縮 (簡單) JavaScript 時的成本。在解析/編譯程式碼方面,市面上速度最快的手機與一般手機之間的差異為 2 至 5 倍。

那麼,實際網站 (例如 CNN.com) 呢?
在高階 iPhone 8 上,剖析/編譯 CNN 的 JS 只需約 4 秒,而一般手機 (Moto G4) 則需要約 13 秒。這可能會大幅影響使用者與這個網站互動的速度。

這也說明瞭測試一般硬體 (例如 Moto G4) 的重要性,而非只測試口袋裡的手機。不過,情境也很重要:請根據使用者的裝置和網路條件進行最佳化調整。

我們是否真的傳送太多 JavaScript?呃,可能會 :)
使用 HTTP 封存庫 (前 50 萬個網站) 分析行動裝置上的 JavaScript 狀態,我們發現 50% 的網站需要超過 14 秒才能變得可互動。這些網站最多會花費 4 秒來剖析及編譯 JavaScript。
考量擷取和處理 JS 和其他資源所需的時間,您可能會發現,使用者必須等待一段時間,才能感覺到網頁已可使用。我們絕對可以做得更好。
從網頁中移除非必要的 JavaScript,可以縮短傳輸時間、減少 CPU 密集的剖析和編譯作業,並降低潛在的記憶體開銷。這也有助於加快網頁的互動速度。
執行時間
除了剖析和編譯之外,JavaScript 執行作業 (在剖析/編譯後執行程式碼) 是必須在主執行緒上執行的作業之一。執行時間過長也會延長使用者與網站互動的時間。
如果指令碼的執行時間超過 50 毫秒,則下載、編譯及執行 JS 所需的時間會全部延遲互動時間 — Alex Russell
為解決這個問題,JavaScript 會以小型區塊的形式運作,避免鎖定主執行緒。探索是否可以減少執行期間的工作量。
其他費用
JavaScript 還可能以其他方式影響網頁效能:
- 記憶體。由於 GC (垃圾收集),頁面可能會經常出現卡頓或暫停的情形。當瀏覽器回收記憶體時,JS 執行作業會暫停,因此經常收集垃圾的瀏覽器可能會比我們預期更頻繁地暫停執行作業。避免記憶體耗損和頻繁的 GC 暫停,確保網頁不會出現卡頓現象。
- 在執行階段中,長時間執行的 JavaScript 可能會封鎖主執行緒,導致頁面沒有回應。將工作細分為較小的部分 (使用
requestAnimationFrame()
或requestIdleCallback()
進行排程),可盡量減少回應速度問題,進而改善Interaction to Next Paint (INP)。
減少 JavaScript 提交成本的模式
若您想讓 JavaScript 的剖析/編譯和網路傳輸時間保持緩慢,可以使用路徑為基礎的區塊化或 PRPL 等模式。
PRPL
PRPL (Push、Render、Pre-cache、Lazy-load) 是一種模式,可透過積極的程式碼分割和快取,為互動性進行最佳化:
讓我們來看看這項功能可能帶來的影響。
我們使用 V8 的執行階段呼叫統計資料,分析熱門行動網站和漸進式網頁應用程式的載入時間。如您所見,許多網站的解析時間 (以橘色標示) 都占了相當大的比例:
Wego 是使用 PRPL 的網站,他們成功維持路徑的解析時間,讓路徑能夠快速完成互動。上述許多其他網站都採用了程式碼分割和效能預算,以便降低 JS 成本。
漸進式啟動
許多網站為了提升內容曝光率,犧牲了互動性。為了在有大型 JavaScript 套件時獲得快速的第一筆繪製,開發人員有時會採用伺服器端轉譯,然後在最終擷取 JavaScript 時「升級」附加事件處理常式。
請注意,這項服務本身會產生費用。1) 您通常會傳送較大的 HTML 回應,這可能會影響互動性;2) 使用者可能會處於奇異的谷中,在 JavaScript 完成處理前,一半的體驗無法實際互動。
漸進式 Bootstrapping 可能會是更好的做法。傳送最基本功能的網頁 (僅包含目前路徑所需的 HTML/JS/CSS)。隨著更多資源到達,應用程式就能以延遲載入的方式取得更多功能。

載入程式碼的速度與檢視畫面內容成正比,是聖杯。PRPL 和漸進式 Bootstrapping 模式可協助您達成這項目標。
結論
傳輸大小對低階網路至關重要。對於 CPU 受限裝置而言,解析時間十分重要。請務必降低這些數值。
團隊發現,採用嚴格的效能預算可有效降低 JavaScript 傳輸和剖析/編譯時間。請參閱艾力克斯羅素的「Can You Afford It?「實際網站效能預算」一文,瞭解行動版預算的相關指南。

如果您要建構以行動裝置為目標的網站,請盡可能使用代表性硬體進行開發,縮短 JavaScript 剖析/編譯時間,並採用效能預算,確保團隊能隨時掌握 JavaScript 成本。
瞭解詳情
- Chrome 開發人員大會 2017 - 現代載入最佳做法
- JavaScript 啟動效能
- 解決網站效能危機 - Nolan Lawson
- 你負擔得起嗎?實際效能預算 — Alex Russell
- 評估網路架構和程式庫 — Kristofer Baxter
- Cloudflare 使用 Brotli 進行壓縮實驗的結果 (請注意,品質較高的動態 Brotli 可能會延遲初始網頁的轉譯,因此請謹慎評估。您可能會想改為靜態壓縮。)
- Performance Futures — Sam Saccone