在某些情況下,服務工作者可能需要主動與其控制的任何有效分頁進行通訊,以便通知特定事件。例如:
- 在安裝新版服務工作者時通知網頁,以便網頁向使用者顯示「Update to refresh」按鈕,讓使用者立即存取新功能。
- 讓使用者知道服務工作者端快取資料的變更,方法是顯示指示,例如:「應用程式現在可離線運作」或「可使用新版內容」。
我們將這類用途稱為「廣播更新」,服務工作者不必從網頁接收訊息即可開始通訊。在本指南中,我們將介紹如何使用標準瀏覽器 API 和 Workbox 程式庫,在網頁和服務工作者之間實作這類通訊。
實際工作環境案例
Tinder
Tinder PWA 會使用 workbox-window
接聽頁面中的重要服務工作者生命週期時刻 (「已安裝」、「已控制」和「已啟用」)。這樣一來,當新的服務工作者開始運作時,就會顯示「Update Available」橫幅,讓使用者可以重新整理 PWA 並存取最新功能:
Squoosh
在 Squoosh PWA 中,當服務工作者快取所有必要的資產,以便離線運作時,就會向網頁傳送訊息,顯示「Ready to work offline」浮動視窗,讓使用者瞭解這項功能:
使用 Workbox
監聽服務工作程生命週期事件
workbox-window
提供簡單的介面,可監聽重要的服務工作程式生命週期事件。實際上,程式庫會使用 updatefound
和 statechange 等用戶端 API,並在 workbox-window
物件中提供較高層級的事件監聽器,方便使用者使用這些事件。
下列頁面程式碼可讓您偵測每次安裝服務工作站新版本的情況,以便向使用者傳達相關資訊:
const wb = new Workbox('/sw.js');
wb.addEventListener('installed', (event) => {
if (event.isUpdate) {
// Show "Update App" banner
}
});
wb.register();
通知網頁快取資料的變更
Workbox 套件 workbox-broadcast-update
提供標準方式,可通知視窗用戶端已更新快取的回應。這類策略通常會搭配 StaleWhileRevalidate 策略使用。
如要廣播更新,請在服務工作者端的策略選項中新增 broadcastUpdate.BroadcastUpdatePlugin
:
import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
import {BroadcastUpdatePlugin} from 'workbox-broadcast-update';
registerRoute(
({url}) => url.pathname.startsWith('/api/'),
new StaleWhileRevalidate({
plugins: [
new BroadcastUpdatePlugin(),
],
})
);
您可以在網頁應用程式中監聽這些事件,如下所示:
navigator.serviceWorker.addEventListener('message', async (event) => {
// Optional: ensure the message came from workbox-broadcast-update
if (event.data.meta === 'workbox-broadcast-update') {
const {cacheName, updatedUrl} = event.data.payload;
// Do something with cacheName and updatedUrl.
// For example, get the cached content and update
// the content on the page.
const cache = await caches.open(cacheName);
const updatedResponse = await cache.match(updatedUrl);
const updatedText = await updatedResponse.text();
}
});
使用瀏覽器 API
如果 Workbox 提供的功能無法滿足您的需求,請使用下列瀏覽器 API 實作「廣播更新」:
Broadcast Channel API
服務工作站會建立 BroadcastChannel 物件,並開始傳送訊息給該物件。任何有意接收這些訊息的內容 (例如網頁) 都可以將 BroadcastChannel
物件例項化,並實作訊息處理常式來接收訊息。
如要通知網頁安裝新的服務工作者,請使用以下程式碼:
// Create Broadcast Channel to send messages to the page
const broadcast = new BroadcastChannel('sw-update-channel');
self.addEventListener('install', function (event) {
// Inform the page every time a new service worker is installed
broadcast.postMessage({type: 'CRITICAL_SW_UPDATE'});
});
頁面會訂閱 sw-update-channel
來監聽這些事件:
// Create Broadcast Channel and listen to messages sent to it
const broadcast = new BroadcastChannel('sw-update-channel');
broadcast.onmessage = (event) => {
if (event.data && event.data.type === 'CRITICAL_SW_UPDATE') {
// Show "update to refresh" banner to the user.
}
};
這項技巧雖然簡單,但有瀏覽器支援方面的限制:在撰寫本文時,Safari 不支援這個 API。
用戶端 API
Client API 提供簡單的方式,可透過服務工作程與多個用戶端進行通訊,方法是對 Client
物件的陣列進行迴迭。
請使用下列服務工作程程式碼,將訊息傳送至最後一個聚焦的分頁:
// Obtain an array of Window client objects
self.clients.matchAll(options).then(function (clients) {
if (clients && clients.length) {
// Respond to last focused tab
clients[0].postMessage({type: 'MSG_ID'});
}
});
網頁會實作訊息處理常式,用於攔截這些訊息:
// Listen to messages
navigator.serviceWorker.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
// Process response
}
};
在將資訊廣播至多個有效分頁的情況下,用戶端 API 是個不錯的選擇。所有主要瀏覽器都支援此 API,但並非所有方法都支援。請先確認瀏覽器支援功能,再使用該功能。
訊息管道
訊息管道需要初始設定步驟,透過從網頁傳遞至服務 worker 的連接埠,建立兩者之間的通訊管道。頁面會將 MessageChannel
物件例項化,並透過 postMessage()
介面將連接埠傳遞至服務工作者:
const messageChannel = new MessageChannel();
// Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
messageChannel.port2,
]);
頁面會在該通訊埠上實作「onmessage」處理常式,以便監聽訊息:
// Listen to messages
messageChannel.port1.onmessage = (event) => {
// Process message
};
服務工作站會接收通訊埠並儲存其參照:
// Initialize
let communicationPort;
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'PORT_INITIALIZATION') {
communicationPort = event.ports[0];
}
});
從這個時間點開始,它可以透過呼叫 port 參照中的 postMessage()
,將訊息傳送至頁面:
// Communicate
communicationPort.postMessage({type: 'MSG_ID' });
MessageChannel
需要初始化連接埠,因此導入作業可能較為複雜,但所有主要瀏覽器都支援這項功能。
後續步驟
在本指南中,我們探討了一個與 Window 和服務工作者通訊相關的特殊案例:「廣播更新」。我們將探討的範例包括監聽重要的服務工作程生命週期事件,以及向網頁傳達內容或快取資料的變更。您可以思考更多有趣的用途,例如服務工作者主動與網頁通訊,而不需要先收到任何訊息。
如要進一步瞭解 Window 和服務工作者通訊的其他模式,請參閱: