網路優先 HTML 的導覽預先載入功能

當服務工作處理程序處理 fetch 事件時,瀏覽器會等待 Service Worker 提供回應,雖然網路要求的延遲時間是等待時間的重要因素,但瀏覽器可能也需要等待 Service Worker 啟動並觸發 fetch 事件回呼。

開機時間會因裝置和功能而異,但所需時間可能相當龐大,如果 CPU 速度緩慢,或是因為環境條件的關係,啟動作業處於受限狀態,有時最長可達半秒。透過 Cache 執行個體提供導覽回應時,避開網路的效能提升幅度可能會超過這個啟動時間。針對傳送至網路的導覽要求,導入 Service Worker 可能會產生明顯的延遲。

輸入導覽預先載入功能

導覽預先載入是一項 Service Worker 功能,可解決服務工作站開機時間造成的延遲。如未啟用導覽預先載入功能,服務工作處理程序的開機程序和應處理的瀏覽要求都會連續發生:

黃色和藍色長條,有兩個區隔顯示連續的動作。第一個區隔以黃色顯示「SW Boot」「導航要求」的藍色部分

這並非理想的做法,但只要啟用導覽預先載入功能,即可確保 Service Worker 開機和瀏覽要求會同時發生,藉此修正此問題:

兩條長條彼此堆疊,並向左對齊,代表兩個並行操作。黃色長條標有「SW 啟動」字樣,藍色長條則標記為「導航要求」。

瀏覽預先載入功能可有效最佳化使用 Service Worker 的網站,但並非在所有情況下都應啟用的功能。具體來說,使用友善快取應用程式殼層的網站不需要瀏覽預先載入,因為快取會將導覽要求提供給應用程式殼層標記,不會發生任何瀏覽延遲。在這些情況下,預先載入的回應會遭到浪費,但成效不佳。

網站無法預先載入 HTML 時,最適合使用導覽預先載入功能。試想網站中的標記回應是動態的,且會隨著驗證狀態等等變化。這類的導覽要求可能會使用網路優先 (或甚至僅限網路) 策略,這時導覽預先載入功能可能會產生巨大的差異。

在 Workbox 中使用導覽預先載入功能

直接在非 Workbox 技術的 Service Worker 中使用導覽預先載入,相當不容易。首先,並非所有瀏覽器都支援這個註解。其次,想做出正確做法並不容易。如要瞭解如何直接使用這項工具,請參閱 Jake Archibald 撰寫的詳細說明

Workbox 可簡化導覽預先載入作業,因為 workbox-navigation-preload 模組的 enable 方法會執行必要的功能支援檢查,並建立 activate 事件監聽器來為您啟用這項功能。

接著,使用 Workbox 以網路優先策略處理常式處理導覽要求,就能在支援瀏覽器時發揮瀏覽預先載入的好處:

import * as navigationPreload from 'workbox-navigation-preload';
import {NetworkFirst, StaleWhileRevalidate} from 'workbox-strategies';
import {registerRoute, NavigationRoute, Route} from 'workbox-routing';
import {precacheAndRoute} from 'workbox-precaching';

// Precache the manifest
precacheAndRoute(self.__WB_MANIFEST);

// Enable navigation preload
navigationPreload.enable();

// Create a new navigation route that uses the Network-first, falling back to
// cache strategy for navigation requests with its own cache. This route will be
// handled by navigation preload. The NetworkOnly strategy will work as well.
const navigationRoute = new NavigationRoute(new NetworkFirst({
  cacheName: 'navigations'
}));

// Register the navigation route
registerRoute(navigationRoute);

// Create a route for image, script, or style requests that use a
// stale-while-revalidate strategy. This route will be unaffected
// by navigation preload.
const staticAssetsRoute = new Route(({request}) => {
  return ['image', 'script', 'style'].includes(request.destination);
}, new StaleWhileRevalidate({
  cacheName: 'static-assets'
}));

// Register the route handling static assets
registerRoute(staticAssetsRoute);

啟用導覽預先載入功能後,Workbox 會回應使用 NetworkFirstNetworkOnly 策略並預先載入回應的導覽要求。

如何判斷瀏覽預先載入是否正常運作?

開發版本中,Workbox 會記錄許多其功能。如要檢查 Workbox 中是否正常運作瀏覽預先載入,請在導航要求期間,在支援的瀏覽器中開啟主控台,您會看到記錄訊息,顯示以下資訊:

Chrome 開發人員工具控制台中的 Workbox 記錄螢幕截圖。由上到下讀到的訊息:「Router is 回應 /」、「使用預先載入的瀏覽要求 for /」以及「使用 NetworkFirst 回應 /」

根據預設,這項記錄功能不會在正式環境中顯示,因此在您將 Service Worker 部署至正式環境時,系統不會顯示這項記錄,但這是驗證導覽預先載入是否正常運作 (和其他做法) 的好方法。

自訂預先載入的回應

使用導覽預先載入功能時,您可能需要在應用程式後端自訂預先載入的回應。當服務工作處理程序從網路串流部分內容時,這就相當實用。

在這類情況下,需要知道預先載入要求是透過設為 true 預設值的 Service-Worker-Navigation-Preload 標頭傳送:

Service-Worker-Navigation-Preload: true

然後,您可以在所選應用程式後端檢查這個標頭,並依自身需求修改回應。如果標頭的預設值因任何原因造成問題,可以在視窗環境中變更。請注意,您要在伺服器中進行任何讀取這個標頭的工作,皆由您自己決定,並且不在 Workbox 的範圍內。

結論

直接使用 Navigation 預先載入並不容易,但相當值得,這麼做可以確保服務工作處理程序不會讓瀏覽器發出瀏覽要求,這是相當值得的。有了 Workbox,您無需耗費太多心力,就可以享有預先載入的導航功能。如要進一步瞭解 workbox-navigation-preload 模組,請參閱其參考說明文件