有些網站可能需要與服務工作人員通訊, 並提供有關結果的通知例如:
- 網頁將一份網址清單傳送給 Service Worker,前往 預先擷取,因此當使用者點擊 快取中已有文件或網頁子資源的連結 瀏覽起來更加快速
- 網頁要求 Service Worker 擷取並快取一系列熱門文章, 也能用於離線用途
將這些類型的非重要工作委派給 Service Worker 的好處是,釋出了 。
本指南將探討如何實作單向網頁 透過標準瀏覽器 API 和 Workbox 程式庫存取 Service Worker。我們將這些類型稱為 用途命令式快取。
正式環境案例
1-800-Flowers.com 透過以下方式,針對服務工作處理程序實作命令式快取 (預先擷取)
開啟 postMessage()
,預先擷取
類別頁面中的熱門商品,可以加快後續瀏覽產品詳細資料頁面的速度。
同時,他們會混合使用不同方法來決定要預先擷取哪些項目:
- 網頁載入時,要求服務工作人員擷取前 9 個項目的 JSON 資料,且 將產生的回應物件新增至快取。
- 而其餘項目會監聽「
mouseover
」 事件,因此在發生 使用者將遊標移到項目上,即可按「需求」觸發擷取資源的擷取作業。
這些方法會使用 Cache API 來儲存 JSON 回應:
當使用者點選某個項目時,可以從快取擷取與該項目相關的 JSON 資料。 而無需前往網路,可使瀏覽速度更快。
使用 Workbox
Workbox 可讓您輕鬆傳送訊息至
透過 workbox-window
套件建立一組模組
用在視窗內容中執行是其他 Workbox 套件的輔助工具
這個容器是在 Service Worker 中執行
如要與服務工作人員通訊頁面,請先取得 已註冊的 Service Worker:
const wb = new Workbox('/sw.js');
wb.register();
接著,您就能直接以宣告方式傳送訊息,省去取得 註冊、檢查啟用,或考慮基礎通訊 API:
wb.messageSW({"type": "PREFETCH", "payload": {"urls": ["/data1.json", "data2.json"]}}); });
Service Worker 會實作 message
處理常式,
聆聽這些訊息您可以選擇傳回回應
非必要:
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'PREFETCH') {
// do something
}
});
使用瀏覽器 API
如果 Workbox 程式庫無法滿足您的需求,您可以按照下列方式實作視窗服務 和工作站通訊。
postMessage API 可用來建立從網頁到服務工作處理程序的單向通訊機制。
網頁呼叫
postMessage()
-
Service Worker 介面:
navigator.serviceWorker.controller.postMessage({
type: 'MSG_ID',
payload: 'some data to perform the task',
});
Service Worker 會實作 message
處理常式,
聆聽這些訊息
self.addEventListener('message', (event) => {
if (event.data && event.data.type === MSG_ID) {
// do something
}
});
{type : 'MSG_ID'}
屬性不是絕對必要屬性,但是讓網頁
傳送不同類型的指示給 Service Worker (亦即「預先擷取」或「清除」
storage')。服務工作站可以根據此旗標,分支成不同的執行路徑。
如果作業成功,使用者就能享有這項福利,但如果沒有這麼做,主要的使用者流程就不會變更。舉例來說,當 1-800-Flowers.com 嘗試預先快取時,網頁並不需要判斷 Service Worker 是否成功。如果有,使用者將可享有更快速的瀏覽體驗。如果不需要前往新頁面,這需要更多時間。
簡單的預先擷取範例
「命令式快取」最常見的應用方式之一是「預先擷取」,意味著擷取 或是特定網址的資源,以便加快瀏覽速度。
在網站上導入預先擷取的方式有不同:
- 在網頁中使用「連結預先擷取代碼」:系統會將資源保存在
5 分鐘的瀏覽器快取,之後資源適用的一般
Cache-Control
規則 或 - 使用服務中的執行階段快取策略,補強前述技巧 工作站,延長預先擷取的生命週期 資源超過這個上限。
針對相對簡單的預先擷取情境,例如預先擷取文件或特定資產 (JS CSS 等)) 執行的技術,就是最適合採用的技術。
如果需要其他邏輯,例如剖析 擷取內部網址,更適合將這項工作完全委派給 Service Worker。
將這些作業類型委派給 Service Worker 有下列優點:
- 卸載擷取和瀏覽後處理的繁重工作 (即將上線), 延遲載入次要執行緒。如此一來,主執行緒就能處理更重要的工作 像是回應使用者互動之類的工作
- 讓多個用戶端 (例如分頁) 重複使用共同功能,甚至呼叫 又不封鎖主執行緒。
預先擷取產品詳細資料頁面
首次使用 postMessage()
,日期為
Service Worker 介面,並將網址陣列傳送至快取:
navigator.serviceWorker.controller.postMessage({
type: 'PREFETCH',
payload: {
urls: [
'www.exmaple.com/apis/data_1.json',
'www.exmaple.com/apis/data_2.json',
],
},
});
在 Service Worker 中實作 message
處理常式,
攔截及處理由任何使用中的分頁傳送的訊息:
addEventListener('message', (event) => {
let data = event.data;
if (data && data.type === 'PREFETCH') {
let urls = data.payload.urls;
for (let i in urls) {
fetchAsync(urls[i]);
}
}
});
在先前的程式碼中,我們導入了名為 fetchAsync()
的小型輔助函式,以便對
網址陣列,並為每個網址發出擷取要求:
async function fetchAsync(url) {
// await response of fetch call
let prefetched = await fetch(url);
// (optionally) cache resources in the service worker storage
}
取得回應後,您就可以依賴資源的快取標頭。在許多情況下
但不會快取資源 (就像產品詳細資料頁面一樣),
no-cache
的 Cache-control
標頭)。在這些情況下,您可以依據下列條件覆寫這個行為:
將擷取的資源儲存在 Service Worker 快取中。這樣的好處是
以便在離線情況下放送
不只是 JSON 資料
從伺服器端點擷取 JSON 資料後,其中通常包含其他 值得預先擷取的功能,例如與第一層相關的圖像或其他端點資料 資料。
假設在本範例中,傳回的 JSON 資料是雜貨購物網站的資訊:
{
"productName": "banana",
"productPic": "https://cdn.example.com/product_images/banana.jpeg",
"unitPrice": "1.99"
}
修改 fetchAsync()
程式碼以疊代產品清單,並快取使用者的主頁橫幅
這些原則
async function fetchAsync(url, postProcess) {
// await response of fetch call
let prefetched = await fetch(url);
//(optionally) cache resource in the service worker cache
// carry out the post fetch process if supplied
if (postProcess) {
await postProcess(prefetched);
}
}
async function postProcess(prefetched) {
let productJson = await prefetched.json();
if (productJson && productJson.product_pic) {
fetchAsync(productJson.product_pic);
}
}
您可以針對這個程式碼新增一些例外狀況處理,例如 404 錯誤。 但使用 Service Worker 預先擷取的好處是,會失敗且失敗 所發生的情況。您可能也可以在 對預先擷取內容進行後續處理,從而更具彈性,並與所得資料分離 處理和處理資料海闊天空,任您發揮。
結論
在本文中,我們介紹了頁面和服務之間「單向」通訊的常見用途。 工作站:命令式快取。本文討論的範例僅供示範一種 這種模式也能應用在其他用途上,例如 視需求快取熱門文章,以便離線閱讀、將文章加入書籤等。
如需更多網頁和服務工作處理程序的通訊模式,請參閱: