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".
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 "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 sản xuất
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:
Squoosh
Trong Squoosh PWA, khi trình chạy dịch vụ đã lưu tất cả thành phần cần thiết vào bộ nhớ đệm để hoạt động khi không có mạng, trình chạy dịch vụ sẽ gửi một 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:
Sử dụng Workbox
Theo dõi các sự kiện trong vòng đời của worker 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 phần nội dung, thư viện sử dụng các API phía máy khách như updatefound
và statechange, đồ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 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 "broadcast updates":
Broadcast Channel API
Trình chạy dịch vụ sẽ 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 thực thể cho đố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ã trình chạy dịch vụ sau để gửi thư đến thẻ được đặt 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ợ. 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 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 sẽ tạo thực thể cho đối tượng MessageChannel
và chuyể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ới 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 của Window và Service worker, hãy xem:
- Hướng dẫn lưu vào bộ nhớ đệm ngầm định: Gọi một trình chạy dịch vụ từ trang để lưu trước tài nguyên vào bộ nhớ đệm (ví dụ: trong các trường hợp tìm nạp trước).
- Thông tin liên lạc hai chiều: Uỷ quyền một tác vụ cho worker dịch vụ (ví dụ: tải xuống nhiều dữ liệu) và thông báo cho trang về tiến trình.