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, trình chạy dịch vụ có thể cần chủ động giao tiếp với bất kỳ thẻ đang hoạt động nào mà nó 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 phiên bản mới của trình chạy dịch vụ được cài đặt để trang có thể hiển thị nút "Cập nhật để làm mới" để người dùng truy cập vào chức năng mới ngay lập tức.
  • Thông báo cho người dùng về thay đổi đối với dữ liệu đã lưu vào bộ nhớ đệm diễn ra ở phía trình chạy dịch vụ bằng cách cho thấy 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 "Phiên bản mới của nội dung hiện có".
Sơ đồ cho thấy một trình chạy dịch vụ đang giao tiếp với trang để gửi nội dung cập nhật.

Chúng tôi sẽ gọi những loại trường hợp sử dụng này, trong đó trình chạy dịch vụ không cần nhận thông báo từ trang để bắt đầu quá trình "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à trình chạy dịch vụ, bằng cách sử dụng các API trình duyệt tiêu chuẩn và Thư viện Workbox.

Trường hợp sản xuất

Tinder

PWA của Tinder sử dụng workbox-window để theo dõi các khoảnh khắc quan trọng trong vòng đời của trình chạy dịch vụ trên trang ("đã cài đặt", "được kiểm soát" và "được kích hoạt"). Theo đó, khi một trình chạy dịch vụ mới xuất hiện, màn hình sẽ hiển thị biểu ngữ "Đã có bản cập nhật" để họ 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ập nhật có sẵn" của ứng dụng web Tinder.
Trong PWA Tinder, nhân viên 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ẽ cho người dùng thấy biểu ngữ "Đã có bản cập nhật".

Tiếng Squoosh

Trong Squoosh PWA, khi nhân viên dịch vụ lưu tất cả tài sản cần thiết vào bộ nhớ đệm để chuyển sang chế độ ngoại tuyến, dịch vụ sẽ gửi thông báo đến trang để hiển thị thông báo ngắn "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 "Sẵn sàng làm việc ngoại tuyến" của ứng dụng web Squoosh.
Trong PWA Squoosh, trình chạy dịch vụ sẽ thông báo một bản cập nhật cho trang khi bộ nhớ đệm sẵn sàng và trang hiển thị thông báo ngắn "Sẵn sàng làm việc khi không có mạng".

Sử dụng Workbox

Theo dõi các sự kiện trong vòng đời của trình chạy dịch vụ

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ụ. Trong trường hợp này, 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 sử dụng những sự kiện này dễ dàng hơn.

Mã trang sau đây giúp bạn phát hiện mỗi khi một phiên bản mới của trình chạy dịch vụ được cài đặt để 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ề những thay đổi đối với 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 các ứng dụng cửa sổ rằng phản hồi được lưu vào bộ nhớ đệm đã được cập nhật. Phương thức này thường được sử dụng nhất cùng với chiến lược Stale dễ dàng xác thực lại.

Để truyền tin cập nhật, hãy thêm broadcastUpdate.BroadcastUpdatePlugin vào các lựa chọn chiến lược ở phía trình chạy 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 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 đủ cho nhu cầu của bạn, hãy sử dụng các API trình duyệt sau để triển khai tính năng "cập nhật thông báo truyền tin":

API kênh truyền phát

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 tới đố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 thực thể cho đối tượng BroadcastChannel và triển khai một trình xử lý thông báo để nhận thông báo.

Để thông báo cho trang khi một trình chạy 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 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à 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 (Client API) cung cấp một cách thức đơn giản để giao tiếp với nhiều ứng dụng qua trình chạy dịch vụ bằng cách lặp lại qua một mảng các đối tượng Client.

Sử dụng mã trình chạy 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 hữu ích cho các trường hợp như truyền phát thông tin đến nhiều thẻ đang hoạt động. API này được mọi trình duyệt chính hỗ trợ, nhưng không phải phương thức nào cũng hỗ trợ API này. Hãy kiểm tra khả năng hỗ trợ của trình duyệt trước khi sử dụng.

Kênh tin nhắn

Kênh thông báo (Message Channel) yêu cầu bước định cấu hình ban đầu bằng cách truyền một cổng từ trang đến trình chạy dịch vụ để thiết lập kênh giao tiếp giữa chúng. Trang này tạo thực thể cho đố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 theo dõi 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
};

Service worker nhận cổng và lưu 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ừ thời điểm đó, ứng dụng có thể gửi thông báo đến trang bằng cách gọi postMessage() trong tệp tham chiếu đến cổng:

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

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

Các bước tiếp theo

Trong hướng dẫn này, chúng ta đã tìm hiểu một trường hợp cụ thể về giao tiếp của Window với Service worker: "broadcast updates" (Cập nhật thông báo truyền tin). Các ví dụ được tìm hiểu bao gồm việc lắng nghe các sự kiện quan trọng trong vòng đời của trình chạy dịch vụ và trao đổi với trang về những thay đổi trong nội dung hoặc dữ liệu đã 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 nhận bất kỳ thông báo nào trước đó.

Để xem thêm các mẫu giao tiếp khác của Window và nhân viên dịch vụ, hãy xem:

Tài nguyên bổ sung