Phát thông báo cập nhật đến các trang bằng trình chạy dịch vụ

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

Trong một số trường hợp, worker dịch vụ có thể cần chủ động giao tiếp với bất kỳ thẻ nào đang hoạt động mà worker đó kiểm soát để thông báo về một sự kiện nhất định. Ví dụ:

  • Thông báo cho trang khi đã cài đặt phiên bản mới của worker dịch vụ để trang có thể hiển thị nút "Cập nhật để làm mới" cho người dùng truy cập ngay vào chức năng mới.
  • Thông báo cho người dùng về thay đổi đối với dữ liệu được lưu vào bộ nhớ đệm đã diễn ra ở phía worker dịch vụ, bằng cách hiển thị một chỉ báo, chẳng hạn như: "Ứng dụng hiện đã sẵn sàng hoạt động khi không có mạng" hoặc "Có phiên bản mới của nội dung".
Sơ đồ cho thấy một worker dịch vụ giao tiếp với trang để gửi nội dung cập nhật.

Chúng ta sẽ gọi những loại trường hợp sử dụng này là trường hợp mà worker dịch vụ không cần nhận thông báo từ trang để bắt đầu giao tiếp "cập nhật thông báo truyền tin". Trong hướng dẫn này, chúng ta sẽ xem xét các cách triển khai loại hình giao tiếp này giữa các trang và worker dịch vụ bằng cách sử dụng API trình duyệt chuẩn và thư viện Workbox.

Trường hợp phát hành công khai

Tinder

Tinder PWA sử dụng workbox-window để theo dõi các thời điểm quan trọng trong vòng đời của worker dịch vụ từ trang ("đã cài đặt", "được kiểm soát" và "đã kích hoạt"). Bằng cách đó, khi một worker dịch vụ mới xuất hiện, worker đó sẽ hiển thị biểu ngữ "Có bản cập nhật" để người dùng có thể làm mới PWA và truy cập vào các tính năng mới nhất:

Ảnh chụp màn hình chức năng "Có bản cập nhật" của ứng dụng web Tinder.
Trong PWA Tinder, trình chạy dịch vụ sẽ thông báo cho trang rằng phiên bản mới đã sẵn sàng và trang sẽ hiển thị cho người dùng biểu ngữ "Có bản cập nhật".

Squoosh

Trong Squoosh PWA, khi worker dịch vụ đã lưu tất cả tài sản cần thiết vào bộ nhớ đệm để hoạt động khi không có mạng, worker dịch vụ sẽ gửi thông báo đến trang để hiển thị thông báo ngắn "Ready to work offline" (Sẵn sàng hoạt động khi không có mạng), cho người dùng biết về tính năng này:

Ảnh chụp màn hình chức năng "Ready to work offline" (Sẵn sàng hoạt động ngoại tuyến) của ứng dụng web Squoosh.
Trong PWA Squoosh, trình chạy dịch vụ sẽ truyền tin cập nhật đến trang khi bộ nhớ đệm đã sẵn sàng và trang sẽ hiển thị thông báo ngắn "Ready to work offline" (Sẵn sàng hoạt động khi không có mạng).

Sử dụng Workbox

Theo dõi các sự kiện trong vòng đời của worker

workbox-window cung cấp một giao diện đơn giản để theo dõi các sự kiện quan trọng trong vòng đời của trình chạy dịch vụ. Về cơ bản, thư viện sử dụng các API phía máy khách như updatefoundstatechange, đồng thời cung cấp trình nghe sự kiện cấp cao hơn trong đối tượng workbox-window, giúp người dùng dễ dàng sử dụng các sự kiện này hơn.

Mã trang sau đây cho phép bạn phát hiện mỗi khi cài đặt phiên bản mới của worker dịch vụ, để bạn có thể thông báo cho người dùng:

const wb = new Workbox('/sw.js');

wb.addEventListener('installed', (event) => {
  if (event.isUpdate) {
    // Show "Update App" banner
  }
});

wb.register();

Thông báo cho trang về các thay đổi trong dữ liệu bộ nhớ đệm

Gói Workbox workbox-broadcast-update cung cấp một cách thức tiêu chuẩn để thông báo cho ứng dụng cửa sổ rằng phản hồi đã lưu vào bộ nhớ đệm đã được cập nhật. Chiến lược này thường được sử dụng cùng với chiến lược StaleWhileRevalidate.

Để truyền tin cập nhật, hãy thêm broadcastUpdate.BroadcastUpdatePlugin vào các tuỳ chọn chiến lược ở phía worker dịch vụ:

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(),
    ],
  })
);

Trong ứng dụng web, bạn có thể theo dõi các sự kiện này như sau:

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();
  }
});

Sử dụng API trình duyệt

Nếu chức năng mà Workbox cung cấp không đủ đáp ứng nhu cầu của bạn, hãy sử dụng các API trình duyệt sau đây để triển khai "thông báo cập nhật":

Broadcast Channel API

Trình chạy dịch vụ tạo một đối tượng BroadcastChannel và bắt đầu gửi thông báo đến đối tượng đó. Mọi ngữ cảnh (ví dụ: trang) muốn nhận các thông báo này đều có thể tạo bản sao của đối tượng BroadcastChannel và triển khai trình xử lý thông báo để nhận thông báo.

Để thông báo cho trang khi một worker dịch vụ mới được cài đặt, hãy sử dụng mã sau:

// 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'});
});

Trang này theo dõi các sự kiện này bằng cách đăng ký 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.
  }
};

Đây là một kỹ thuật đơn giản, nhưng hạn chế của kỹ thuật này là khả năng hỗ trợ trình duyệt: tại thời điểm viết bài này, Safari không hỗ trợ API này.

API ứng dụng

API ứng dụng cung cấp một cách thức giao tiếp đơn giản với nhiều ứng dụng từ worker dịch vụ bằng cách lặp lại một mảng các đối tượng Client.

Sử dụng mã worker dịch vụ sau đây để gửi thông báo đến thẻ được lấy tiêu điểm gần đây nhất:

// 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'});
  }
});

Trang này triển khai một trình xử lý thông báo để chặn các thông báo này:

// Listen to messages
navigator.serviceWorker.onmessage = (event) => {
     if (event.data && event.data.type === 'MSG_ID') {
         // Process response
   }
};

API ứng dụng là một lựa chọn tuyệt vời cho các trường hợp như truyền thông tin đến nhiều thẻ đang hoạt động. Tất cả trình duyệt lớn đều hỗ trợ API này, nhưng không phải tất cả phương thức của API đều được hỗ trợ. Kiểm tra khả năng hỗ trợ trình duyệt trước khi sử dụng.

Kênh tin nhắn

Kênh thông báo yêu cầu một bước định cấu hình ban đầu, bằng cách truyền một cổng từ trang đến worker dịch vụ để thiết lập một kênh giao tiếp giữa các cổng đó. Trang này tạo bản sao của đối tượng MessageChannel và truyền một cổng đến trình chạy dịch vụ thông qua giao diện postMessage():

const messageChannel = new MessageChannel();

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

Trang này nghe thông báo bằng cách triển khai trình xử lý "onmessage" trên cổng đó:

// Listen to messages
messageChannel.port1.onmessage = (event) => {
  // Process message
};

Trình chạy dịch vụ nhận cổng và lưu thông tin tham chiếu đến cổng đó:

// Initialize
let communicationPort;

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PORT_INITIALIZATION') {
    communicationPort = event.ports[0];
  }
});

Từ đó, ứng dụng có thể gửi thông báo đến trang bằng cách gọi postMessage() trong tham chiếu đến cổng:

// Communicate
communicationPort.postMessage({type: 'MSG_ID' });

MessageChannel có thể phức tạp hơn để triển khai do cần khởi chạy cổng, nhưng tất cả trình duyệt chính đều hỗ trợ phương thức này.

Các bước tiếp theo

Trong hướng dẫn này, chúng tôi đã khám phá một trường hợp cụ thể về cách giao tiếp giữa Cửa sổ và worker dịch vụ: "thông báo cập nhật". Các ví dụ được khám phá bao gồm việc nghe các sự kiện quan trọng trong vòng đời của worker dịch vụ và giao tiếp với trang về những thay đổi trong nội dung hoặc dữ liệu được lưu vào bộ nhớ đệm. Bạn có thể nghĩ đến các trường hợp sử dụng thú vị hơn, trong đó worker dịch vụ chủ động giao tiếp với trang mà không cần nhận bất kỳ thông báo nào trước đó.

Để biết thêm các mẫu giao tiếp giữa Window và worker dịch vụ, hãy xem:

Tài nguyên khác