與服務工作人員之間的雙向通訊

Andrew Guan
Andrew Guan
Demián Renzulli
Demián Renzulli

在某些情況下,網頁應用程式可能需要在兩個執行個體之間建立「雙向」通訊管道。 和 Service Worker。

舉例來說,在 Podcast PWA 中,您可建構讓使用者下載單集節目的功能 離線消費 服務工作處理程序來定期將進度通知網頁,因此 執行緒可能會更新 UI。

本指南將說明在兩個平台之間執行雙向通訊的各種方法。 視窗服務 工作站背景資訊 不同的 API、Workbox 程式庫 例如幾種進階用途

顯示 Service Worker 和交換訊息的頁面示意圖。

使用 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 的功能

這張圖表顯示使用 Workbox 視窗,頁面與服務工作處理程序之間進行雙向通訊。

使用 Browser API

如果 Workbox 程式庫無法滿足您的需求,有多種低階 API 可供使用 導入頁面和服務工作站之間的雙向通訊。兩者的相似之處 以及差異之處:

相似處:

  • 無論如何,通訊都會透過 postMessage() 介面開始,並接收 實作 message 處理常式。
  • 實際上,所有可用的 API 都能實現相同的用途,其中有些 API 某些情況下的開發工作可能較為繁複

差別:

  • 他們會以不同的方式識別通訊的另一端:有些人會使用 明確參照其他情境,而其他人則可以透過 Proxy 以隱含方式溝通 且會在各邊建立例項
  • 瀏覽器支援會因瀏覽器而異。
這張圖表顯示頁面和 Service Worker,以及可用的瀏覽器 API 之間的雙向通訊。

廣播頻道 API

瀏覽器支援

  • Chrome:54。
  • Edge:79,
  • Firefox:38。
  • Safari:15.4。

資料來源

Broadcast Channel API 可讓瀏覽環境間透過 BroadcastChannel 進行基本通訊 物件

如要實作,第一個結構定義必須使用相同 ID 將 BroadcastChannel 物件例項化 以及透過以下應用程式收發訊息:

const broadcast = new BroadcastChannel('channel-123');

BroadcastChannel 物件會公開 postMessage() 介面,以便將訊息傳送給任何監聽 背景資訊:

//send message
broadcast.postMessage({ type: 'MSG_ID', });

任何瀏覽器結構定義都可以透過 BroadcastChannelonmessage 方法監聽訊息 物件:

//listen to messages
broadcast. => {
  if (event.data && event.data.type === 'MSG_ID') {
    //process message...
  }
};

如您所見,沒有明確參照特定情境,所以不需要取得特定情境的 Service Worker 或任何特定用戶端。

這張圖表顯示使用 Broadcast Channel 物件,網頁和 Service Worker 之間的雙向通訊。

缺點是,在本文撰寫期間,API 支援 Chrome、Firefox 和 Edge,但 Safari 等其他瀏覽器不支援 。

用戶端 API

瀏覽器支援

  • Chrome:40.
  • Edge:17。
  • Firefox:44。
  • Safari:11.1.

資料來源

Client API 可讓您取得 參照所有 WindowClient 物件,代表服務工作處理程序所控制的使用中分頁。

由於網頁是由單一 Service Worker 控管,因此會監聽並傳送訊息至 透過 serviceWorker 介面直接使用有效的 Service Worker:

//send message
navigator.serviceWorker.controller.postMessage({
  type: 'MSG_ID',
});

//listen to messages
navigator.serviceWorker. => {
  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

訊息管道

瀏覽器支援

  • Chrome:2.
  • Edge:12.
  • Firefox:41。
  • Safari:5.

資料來源

訊息頻道需要 從一個結構定義到另一個結構定義,定義並傳遞通訊埠,來建立「雙向」通訊 頻道。

如要初始化管道,頁面會將 MessageChannel 物件例項化並使用該物件 ,將通訊埠傳送至已註冊的 Service Worker。這個網頁也會在onmessage 接收來自其他情境的訊息:

const messageChannel = new MessageChannel();

//Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
  messageChannel.port2,
]);

//Listen to messages
messageChannel.port1. => {
  // Process message
};
圖表顯示一個頁面將通訊埠傳遞至 Service Worker,用來建立雙向通訊的頁面。

服務工作處理程序接收到通訊埠、儲存對其參照,並使用它來傳送訊息到另一個 側:

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 來處理特定 情境:沒有網路連線且下載時間過長。

背景同步處理

瀏覽器支援

  • Chrome:49.
  • Edge:79,
  • Firefox:不支援。
  • Safari:不支援。

資料來源

即時通訊應用程式或許會想確保訊息不會因連線品質不佳而遺失。 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 搜尋會使用背景同步處理功能,保留因連線品質不佳而失敗的查詢;並重試 等到使用者連上網路後執行作業後,他們會將結果傳送到 透過網路推播通知:

圖表顯示一個頁面將通訊埠傳遞至 Service Worker,用來建立雙向通訊的頁面。

背景擷取

瀏覽器支援

  • Chrome:74.
  • Edge:79,
  • Firefox:不支援。
  • Safari:不支援。

資料來源

如果是相對較短的工作 (例如傳送郵件或快取網址清單),選項 是個很好的選擇如果工作執行時間過長,瀏覽器會終止服務 否則就會危及使用者隱私和電池。

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,用來建立雙向通訊的頁面。
畫面更新後,使用者介面會顯示下載進度 (左側)。有了服務工作人員的協助,當所有分頁都關閉時 (右側),作業就會繼續執行。
,瞭解如何調查及移除這項存取權。

後續步驟

在本指南中,我們探討了頁面與服務工作人員之間的最常見的通訊案例 (雙向通訊)。

很多時候,可能只需要一個背景資訊就能相互通訊,且無須接收 回應。請參閱下列指南,瞭解如何在 向 Service Worker 傳送網頁,以及使用案例和實際執行範例:

  • 命令式快取指南:從網頁呼叫服務工作人員, 預先擷取快取資源 (例如在預先擷取的情況下)。
  • 廣播更新:向服務工作人員呼叫網頁通知 查看重要更新 (例如有新版網頁應用程式可用)。