在某些情況下,Service Worker 可能需要主動與其控制的任何啟用分頁進行通訊,以便通知特定事件。例如:
- 在新版 Service Worker 安裝完成後通知頁面,讓使用者能立即顯示「更新以重新整理」按鈕,以便立即存取新功能。
- 藉由顯示下列指示,讓使用者瞭解服務工作站端的快取資料發生變更,例如:「應用程式已準備好可離線工作」或「有新版本的內容可用」。
針對這樣,Service Worker 不需要收到網頁訊息就可以開始通訊「廣播更新」訊息,而我們將這類用途稱為「廣播更新」。本指南將說明使用標準瀏覽器 API 和 Workbox 程式庫,在頁面與服務工作站之間實作這類通訊的方式。
正式環境
Tinder
Tinder PWA 會使用 workbox-window
監聽頁面中的重要 Service Worker 生命週期時刻 (「已安裝」、「受控管」和「已啟用」)。這樣一來,新的 Service Worker 就會在啟動時顯示「有可用的更新」橫幅,方便他們重新整理 PWA 並存取最新功能:
壁球
在 Squoosh PWA 中,如果服務工作站已快取所有必要的資產,使其可以離線運作,便會向頁面傳送訊息,顯示「可以離線運作」的浮動式訊息,讓使用者瞭解這項功能:
使用 Workbox
監聽 Service Worker 生命週期事件
workbox-window
提供簡單明瞭的介面,可監聽重要的 Service Worker 生命週期事件。基本上,程式庫會使用用戶端 API (例如 updatefound
和狀態變更),並在 workbox-window
物件中提供更高層級的事件監聽器,讓使用者更容易使用這些事件。
下列頁面程式碼可讓您在每次安裝新版 Service Worker 時偵測,以便您與使用者溝通:
const wb = new Workbox('/sw.js');
wb.addEventListener('installed', (event) => {
if (event.isUpdate) {
// Show "Update App" banner
}
});
wb.register();
通知頁面快取資料的變更
Workbox 套件 workbox-broadcast-update
提供一種標準方法,可通知視窗用戶端快取回應已更新。這個方法最常與 StaleAtRevalidate 策略搭配使用。
如要播送更新,請在 Service Worker 端,新增 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
Service Worker 會建立 BroadcastChannel 物件,並開始傳送訊息。凡是有意接收這些訊息的情境 (例如頁面),都可以將 BroadcastChannel
物件例項化,並實作訊息處理常式來接收訊息。
如要在安裝新的 Service Worker 時通知網頁,請使用下列程式碼:
// 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
物件陣列,方便您從服務工作站與多個用戶端通訊。
使用下列 Service Worker 程式碼,將訊息傳送至最後一個聚焦的分頁:
// 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
}
};
Client API 非常適合用於將資訊廣播至多個使用中的分頁。所有主要瀏覽器都支援此 API,但並非所有方法都支援。使用前請先檢查瀏覽器支援。
訊息管道
訊息管道需要初始設定步驟,方法是將通訊埠從頁面傳遞至服務工作站,藉此在其之間建立通訊通道。該頁面會透過 postMessage()
介面將 MessageChannel
物件例項化,並將通訊埠傳送至 Service Worker:
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];
}
});
此時,您便可在通訊埠的參照中呼叫 postMessage()
,藉此傳送訊息至頁面:
// Communicate
communicationPort.postMessage({type: 'MSG_ID' });
MessageChannel
的實作可能較為複雜,因為需要初始化通訊埠,但所有主要瀏覽器都支援這項功能。
後續步驟
在本指南中,我們探討了單一 Window 至服務工作站通訊的情況:"廣播更新"。探索的範例包括監聽重要的 Service Worker 生命週期事件,以及針對內容或快取資料的變更通知網頁。您可以想出更有趣的使用情境,讓服務工作站主動與網頁通訊,而不到先前收到任何訊息的情況。
如要進一步瞭解 Window 和 Service Worker 的通訊模式,請參閱: