在某些情況下,網頁應用程式可能需要在兩個執行個體之間建立「雙向」通訊管道。 和 Service Worker。
舉例來說,在 Podcast PWA 中,您可建構讓使用者下載單集節目的功能 離線消費 服務工作處理程序來定期將進度通知網頁,因此 執行緒可能會更新 UI。
本指南將說明在兩個平台之間執行雙向通訊的各種方法。 視窗和服務 工作站背景資訊 不同的 API、Workbox 程式庫 例如幾種進階用途
使用 Workbox
workbox-window
是一組
Workbox 程式庫的預期模組
要在視窗內容中執行Workbox
類別提供 messageSW()
方法,可將訊息傳送至執行個體的註冊 Service Worker,並
等待回應。
下列頁面程式碼會建立新的 Workbox
執行個體,並傳送訊息給 Service Worker
以便取得該版本:
const wb = new Workbox('/sw.js');
wb.register();
const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);
服務工作處理程序在另一端實作訊息事件監聽器,並回應已註冊的 Service Worker:
const SW_VERSION = '1.0.0';
self.addEventListener('message', (event) => {
if (event.data.type === 'GET_VERSION') {
event.ports[0].postMessage(SW_VERSION);
}
});
實際上,程式庫會使用瀏覽器 API,我們會在下一節進行說明: 管道,但抽象 導入細節,更易於使用,同時採用寬版瀏覽器 支援這個 API 的功能
使用 Browser API
如果 Workbox 程式庫無法滿足您的需求,有多種低階 API 可供使用 導入頁面和服務工作站之間的雙向通訊。兩者的相似之處 以及差異之處:
相似處:
- 無論如何,通訊都會透過
postMessage()
介面開始,並接收 實作message
處理常式。 - 實際上,所有可用的 API 都能實現相同的用途,其中有些 API 某些情況下的開發工作可能較為繁複
差別:
- 他們會以不同的方式識別通訊的另一端:有些人會使用 明確參照其他情境,而其他人則可以透過 Proxy 以隱含方式溝通 且會在各邊建立例項
- 瀏覽器支援會因瀏覽器而異。
廣播頻道 API
Broadcast Channel API 可讓瀏覽環境間透過 BroadcastChannel 進行基本通訊 物件。
如要實作,第一個結構定義必須使用相同 ID 將 BroadcastChannel
物件例項化
以及透過以下應用程式收發訊息:
const broadcast = new BroadcastChannel('channel-123');
BroadcastChannel 物件會公開 postMessage()
介面,以便將訊息傳送給任何監聽
背景資訊:
//send message
broadcast.postMessage({ type: 'MSG_ID', });
任何瀏覽器結構定義都可以透過 BroadcastChannel
的 onmessage
方法監聽訊息
物件:
//listen to messages
broadcast.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//process message...
}
};
如您所見,沒有明確參照特定情境,所以不需要取得特定情境的 Service Worker 或任何特定用戶端。
缺點是,在本文撰寫期間,API 支援 Chrome、Firefox 和 Edge,但 Safari 等其他瀏覽器不支援 。
用戶端 API
Client API 可讓您取得
參照所有 WindowClient
物件,代表服務工作處理程序所控制的使用中分頁。
由於網頁是由單一 Service Worker 控管,因此會監聽並傳送訊息至
透過 serviceWorker
介面直接使用有效的 Service Worker:
//send message
navigator.serviceWorker.controller.postMessage({
type: 'MSG_ID',
});
//listen to messages
navigator.serviceWorker.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//process response
}
};
同樣地,服務工作站會實作 onmessage
事件監聽器來監聽訊息:
//listen to messages
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//Process message
}
});
為了與任何用戶端通訊,服務工作人員會取得
WindowClient
物件,方法是執行
取得
Clients.matchAll()
和
Clients.get()
。接著
postMessage()
任何:
//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'});
}
});
Client API
很適合用來與 Service Worker 的所有使用中分頁通訊
幫助新聞機構
以相對簡單直接的方式操作這個 API 受到所有主要版本支援的
瀏覽器
並不是所有方法都適用,因此請務必先檢查瀏覽器支援
導入這個 API
訊息管道
訊息頻道需要 從一個結構定義到另一個結構定義,定義並傳遞通訊埠,來建立「雙向」通訊 頻道。
如要初始化管道,頁面會將 MessageChannel
物件例項化並使用該物件
,將通訊埠傳送至已註冊的 Service Worker。這個網頁也會在onmessage
接收來自其他情境的訊息:
const messageChannel = new MessageChannel();
//Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
messageChannel.port2,
]);
//Listen to messages
messageChannel.port1.onmessage = (event) => {
// Process message
};
服務工作處理程序接收到通訊埠、儲存對其參照,並使用它來傳送訊息到另一個 側:
let communicationPort;
//Save reference to port
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'PORT_INITIALIZATION') {
communicationPort = event.ports[0];
}
});
//Send messages
communicationPort.postMessage({type: 'MSG_ID'});
「MessageChannel
」目前受到所有主要版本支援
瀏覽器。
進階 API:背景同步處理和背景擷取
在本指南中,我們探討瞭如何導入雙向通訊技術, 單純的情境,例如傳送描述要執行的作業的字串訊息,或是網址清單 在不同內容之間快取本節將探討兩個 API 來處理特定 情境:沒有網路連線且下載時間過長。
背景同步處理
即時通訊應用程式或許會想確保訊息不會因連線品質不佳而遺失。 Background Sync API 可讓您 系統會在使用者連線穩定時,延遲重試動作。這有助於確保 任何使用者想要傳送的內容
頁面會註冊 sync
,而不是 postMessage()
介面:
navigator.serviceWorker.ready.then(function (swRegistration) {
return swRegistration.sync.register('myFirstSync');
});
然後,Service Worker 會監聽 sync
事件以處理訊息:
self.addEventListener('sync', function (event) {
if (event.tag == 'myFirstSync') {
event.waitUntil(doSomeStuff());
}
});
doSomeStuff()
函式應會傳回承諾,指出其成功/失敗
嘗試這麼做如果有執行完畢,就表示同步處理作業已完成。如果失敗,系統將排定另一項同步處理作業:
重試。重試同步處理作業也會等待連線能力,並以指數輪詢方式執行。
作業執行完畢後,服務工作處理程序就可以與頁面通訊, 使用先前介紹的任何通訊 API 更新使用者介面
Google 搜尋會使用背景同步處理功能,保留因連線品質不佳而失敗的查詢;並重試 等到使用者連上網路後執行作業後,他們會將結果傳送到 透過網路推播通知:
背景擷取
如果是相對較短的工作 (例如傳送郵件或快取網址清單),選項 是個很好的選擇如果工作執行時間過長,瀏覽器會終止服務 否則就會危及使用者隱私和電池。
Background Fetch API 你可以將長時間工作卸載給服務工作人員,例如下載電影、Podcast 或關卡
如要從頁面與 Service Worker 通訊,請使用 backgroundFetch.fetch
(而不是
postMessage()
:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.fetch(
'my-fetch',
['/ep-5.mp3', 'ep-5-artwork.jpg'],
{
title: 'Episode 5: Interesting things.',
icons: [
{
sizes: '300x300',
src: '/ep-5-icon.png',
type: 'image/png',
},
],
downloadTotal: 60 * 1024 * 1024,
},
);
});
BackgroundFetchRegistration
物件可讓網頁監聽 progress
事件
下載進度:
bgFetch.addEventListener('progress', () => {
// If we didn't provide a total, we can't provide a %.
if (!bgFetch.downloadTotal) return;
const percent = Math.round(
(bgFetch.downloaded / bgFetch.downloadTotal) * 100,
);
console.log(`Download progress: ${percent}%`);
});
後續步驟
在本指南中,我們探討了頁面與服務工作人員之間的最常見的通訊案例 (雙向通訊)。
很多時候,可能只需要一個背景資訊就能相互通訊,且無須接收 回應。請參閱下列指南,瞭解如何在 向 Service Worker 傳送網頁,以及使用案例和實際執行範例: