將傳統的預先擷取技術與服務工作人員相輔相成。
在網站上執行工作通常需要幾個步驟。舉例來說,在電子商務網站上購買產品時,可能會用到搜尋產品、從結果清單中挑選商品、將商品加入購物車,以及完成結帳。
從技術層面來說,瀏覽不同頁面就等於發出導覽要求。一般來說,您不應使用長效 Cache-Control
標頭,為導覽要求快取 HTML 回應。這些要求通常會透過 Cache-Control: no-cache
的網路回應,確保 HTML 和後續網路要求鏈 (合理) 都是最新的。使用者每次瀏覽至新網頁時,都必須先連上網路,因此每次瀏覽的速度可能會變慢;如果甚至,則表示瀏覽速度不「穩定」。
為了加快處理速度,如果您能預測使用者的動作,就可以提前要求這些網頁和資產,並保留在快取中一小段時間,直到使用者點選這些連結為止。這種做法稱為「預先載入」,通常會在網頁中加入 <link rel="prefetch">
標記,指出要預先載入的資源。
在本指南中,我們將探討服務工作者可用於補足傳統預先擷取技術的各種方式。
實際工作環境案例
MercadoLibre 是拉丁美洲最大的電子商務網站。為了加快導覽速度,這些程式會在流程的部分部分動態插入 <link rel="prefetch">
標記。舉例來說,在資訊頁面中,只要使用者捲動到資訊底部,系統就會擷取下一頁的結果:
預先擷取的檔案會以「最低」優先順序要求,並儲存在 HTTP 快取或 記憶體快取中 (視資源是否可快取而定),時間長短視瀏覽器而定。舉例來說,在 Chrome 85 中,這個值為 5 分鐘。資源會保留五分鐘,之後就會套用資源的一般 Cache-Control
規則。
使用 Service Worker 快取,可延長預先擷取資源的生命週期超過五分鐘。
舉例來說,義大利體育網站 Virgilio Sport 使用服務工作者,在首頁預先擷取最熱門的貼文。他們也會使用 Network Information API,避免為使用 2G 連線的使用者預先載入。
因此,在觀察了 3 週後,Virgilio Sport 的文章導覽載入時間改善了 78%,文章曝光次數也增加了 45%。
使用 Workbox 實作預先快取
在下一節中,我們將使用 Workbox 示範如何在 Service Worker 中實作不同的快取技術,這些技術可以用來輔助 <link rel="prefetch">
或甚至取代 API,也就是將這項工作完全委派給服務工作站。
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">
- 將網頁子資源新增至 Service 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. 將預先擷取作業委派給 Service Worker
在大多數情況下,最佳做法是使用 <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
}
});