透過 Service Worker 向網頁廣播更新

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

在某些情況下,服務工作處理程序可能需要主動與 標籤,藉此告知特定事件。例如:

  • 在安裝新版本的 Service Worker 時通知頁面,使頁面 可以向使用者顯示「更新以重新整理」按鈕,讓他們使用新功能 立即生效
  • 透過下列方式,告知使用者服務工作處理程序端的快取資料異動: 上出現類似這樣的圖示:「應用程式已可離線使用」新版 內容」
這張圖表顯示服務工作人員正在與網頁通訊以傳送更新。

我們會呼叫這些類型的用途,讓 Service Worker 不需要接收來自 Service Worker 的訊息 開始與「廣播更新」通訊。在本指南中,我們將探討 讓頁面和服務工作人員透過 瀏覽器 API 和 Workbox 程式庫

正式環境案例

Tinder

Tinder PWA 使用 workbox-window 聆聽 網頁中的重要 Service Worker 生命週期片段 (「已安裝」、「控制」和 「已啟用」)。這樣新的服務工作處理程序開始時,就會顯示「有可用的更新」 橫幅,更新 PWA 並使用最新功能:

Tinder 網頁應用程式「有更新」的螢幕截圖功能。
在 Tinder PWA 中,服務工作處理程序會告知網頁新版本已就緒,然後使用者會在頁面上看到「有可用的更新」橫幅。

紅杉

Squoosh PWA 中,當 Service Worker 快取了所有需要的 素材資源會先傳到網頁,並顯示「可離線使用」訊息 浮動式訊息,讓使用者瞭解這項功能:

Squoosh Web 應用程式「已可離線運作」的螢幕截圖功能。
在 Squoosh PWA 中,服務工作處理程序會在快取準備就緒時播送頁面更新,並顯示「已可離線運作」浮動式訊息:

使用 Workbox

監聽 Service Worker 生命週期事件

workbox-window 提供簡單明瞭的介面,方便您監聽重要的 Service Worker 生命週期 事件。 程式庫實際上會使用以下用戶端 API: updatefound敬上 和 statechange 並在 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敬上 提供了一種標準方法,可讓視窗用戶端通知快取回應已更新。這是 最常與 SnarWithRevalidate 驗證 策略

如要播送更新,請在以下策略選項中加入 broadcastUpdate.BroadcastUpdatePlugin: Service Worker 端:

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:

廣播頻道 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 是簡單明瞭的 可透過疊代陣列的陣列,與 Service Worker 的多個用戶端進行通訊 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,但並非所有方法都支援 API。先檢查瀏覽器支援 利用 Vertex AI Workbench 使用者

訊息管道

訊息頻道需要 初始設定步驟,方法是將通訊埠從網頁傳遞至 Service Worker,以建立 與其他通訊管道頁面會將 MessageChannel 物件例項化,並傳遞 或是透過 postMessage() 介面連線至 Service 工作站:

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 生命週期事件,以及向頁面說明內容或快取資料變更。您可以思考 多種有趣的應用實例,也就是服務工作處理程序主動與網頁通訊 而不接收任何訊息

如需更多視窗和 Service Worker 的通訊模式,請參閱:

  • 命令式快取指南:從網頁呼叫服務工作人員, 預先擷取快取資源 (例如在預先擷取的情況下)。
  • 雙向通訊:將工作委派給 Service Worker (例如 可大幅加快下載速度),並隨時透過頁面瞭解進度。

其他資源