透過服務工作者補足傳統預先載入技術。
在網站上執行任務通常需要完成多個步驟。舉例來說,在電子商務網站上購買產品可能會涉及搜尋產品、從結果清單中挑選商品、將商品加入購物車,以及透過結帳完成操作。
從技術層面來說,瀏覽不同頁面就是發出導覽要求。一般來說,您不應使用長效 Cache-Control
標頭,為導覽要求快取 HTML 回應。通常應透過網路和 Cache-Control: no-cache
滿足這些需求,確保 HTML 和後續網路要求鏈結 (合理) 保持新鮮。每次使用者前往新網頁時都必須透過網路,因此每個導覽可能都會變慢,至少不會穩定地快速。
為了加快這些要求的速度,如果您可以預測使用者的動作,可以事先要求這些網頁和素材資源,並將這些內容保留在快取中一段時間,直到使用者點選這些連結為止。這種做法稱為「預先載入」prefetching,通常會在網頁中加入 <link rel="prefetch">
標記,指出要預先載入的資源。
在本指南中,我們將探討服務工作者可用於補足傳統預先擷取技術的各種方式。
實際工作環境案例
MercadoLibre 是拉丁美洲最大的電子商務網站。為了加快導覽速度,這些程式會在流程的部分部分動態插入 <link rel="prefetch">
標記。舉例來說,在資訊頁面中,只要使用者捲動到資訊底部,系統就會擷取下一頁的結果:
預先擷取的檔案會以「最低」優先順序要求,並儲存在 HTTP 快取或 記憶體快取中 (視資源是否可快取而定),時間長短視瀏覽器而定。舉例來說,在 Chrome 85 中,這個值為 5 分鐘。資源會保留五分鐘,之後就會套用資源的一般 Cache-Control
規則。
使用服務工作者快取功能,有助於延長預先快取資源的生命週期,超過五分鐘的時間範圍。
舉例來說,義大利體育網站 Virgilio Sport 使用服務工作者,在首頁預先擷取最熱門的貼文。他們也會使用 Network Information API,避免為使用 2G 連線的使用者預先載入。
因此,在觀察了 3 週後,Virgilio Sport 的文章導覽載入時間改善了 78%,文章曝光次數也增加了 45%。
使用 Workbox 實作預先快取
在下一節中,我們將使用 Workbox 說明如何在服務工作站中實作不同的快取技術,以便在將此工作完全委派給服務工作站時,做為 <link rel="prefetch">
的補充,甚至是替代方案。
1. 預先快取靜態網頁和網頁子資源
預先快取是指服務工作者在安裝時,將檔案儲存到快取的功能。
在以下情況下,預先快取可用於達成與預先載入相同的目標:加快導覽速度。
預先快取靜態網頁
如果是建構期間產生的網頁 (例如 about.html
、contact.html
),或是完全靜態網站,您只需將網站文件加入預快取清單,這樣使用者每次存取時,這些文件就會在快取中提供:
workbox.precaching.precacheAndRoute([
{url: '/about.html', revision: 'abcd1234'},
// ... other entries ...
]);
預先快取網頁子資源
一般最佳做法是預先快取網站不同部分可能會使用的靜態素材資源 (例如 JavaScript、CSS 等),這樣做可在預先快取情境中提供額外提升效果。
如要加快電子商務網站中的導覽速度,您可以在產品資訊頁面中使用 <link rel="prefetch">
標記,為產品資訊頁面中前幾項產品的產品詳細資料頁面預先載入。如果您已預先快取產品頁面子資源,這項功能還能讓導覽速度更快。
實作方式如下:
- 在頁面中加入
<link rel="prefetch">
標記:
<link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
- 將網頁子資源新增至服務 worker 中的預先快取清單:
workbox.precaching.precacheAndRoute([
'/styles/product-page.ac29.css',
// ... other entries ...
]);
2. 延長預先載入資源的生命週期
如先前所述,<link rel="prefetch">
會在 HTTP 快取中擷取及保留資源一段時間,之後資源的 Cache-Control
規則就會套用。在 Chrome 85 中,這個值為 5 分鐘。
服務工作者可讓您延長預先載入頁面的生命週期,同時提供額外的好處,讓這些資源可供離線使用。
在前述範例中,您可以使用 Workbox 執行階段快取策略,補充用於預先擷取產品頁面的 <link rel="prefetch">
。
實作方式如下:
- 在頁面中加入
<link rel="prefetch">
標記:
<link rel="prefetch" href="/phones/smartphone-5x.html" as="document">
- 針對以下類型的要求,在服務工作站中實作執行階段快取策略:
new workbox.strategies.StaleWhileRevalidate({
cacheName: 'document-cache',
plugins: [
new workbox.expiration.Plugin({
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
}),
],
});
在本例中,我們選擇使用「Stale-while-revalidate」策略。在這種策略中,系統可以同時從快取和網路要求網頁。回應會從快取 (如有) 取得,如果沒有,則從網路取得。每次成功要求時,快取都會與網路回應保持一致。
3. 將預先載入工作委派給服務工作站
在大多數情況下,使用 <link rel="prefetch">
是最佳做法。這個標記是資源提示,旨在盡可能提高預先載入的效率。
不過,在某些情況下,將這項工作完全委派給服務工作可能會比較好。舉例來說,如要在用戶端算繪的產品資訊頁面中預先擷取前幾項產品,可能需要根據 API 回應,在頁面中動態插入多個 <link rel="prefetch">
標記。這可能會暫時耗用網頁主執行緒的時間,並使實作更加困難。
在這種情況下,請使用「頁面至服務工作程溝通策略」,將預先載入的任務完全委派給服務工作程。您可以使用 worker.postMessage() 實現這類通訊:
Workbox Window 套件可簡化這類通訊,抽象化底層呼叫的許多細節。
您可以透過下列方式實作 Workbox 視窗的預先載入功能:
- 在頁面中:呼叫 Service Worker,並傳遞訊息類型和要預先載入的網址清單:
const wb = new Workbox('/sw.js');
wb.register();
const prefetchResponse = await wb.messageSW({type: 'PREFETCH_URLS', urls: […]});
- 在 Service Worker 中:實作訊息處理常式,針對每個要預先載入的網址發出
fetch()
要求:
addEventListener('message', (event) => {
if (event.data.type === 'PREFETCH_URLS') {
// Fetch URLs and store them in the cache
}
});