ในบางสถานการณ์ โปรแกรมทำงานของบริการอาจต้องสื่อสารกับแท็บที่ใช้งานอยู่ที่ควบคุมอยู่เองเพื่อแจ้งเหตุการณ์บางอย่าง ตัวอย่างเช่น
- แจ้งให้หน้าเว็บทราบเมื่อติดตั้ง Service Worker เวอร์ชันใหม่แล้ว เพื่อให้หน้าเว็บแสดงปุ่ม "อัปเดตเพื่อรีเฟรช" แก่ผู้ใช้เพื่อเข้าถึงฟังก์ชันการทำงานใหม่ได้ทันที
- แจ้งให้ผู้ใช้ทราบเกี่ยวกับการเปลี่ยนแปลงในข้อมูลที่แคชไว้ซึ่งเกิดขึ้นในฝั่งของ Service Worker โดยแสดงตัวบ่งชี้ เช่น "แอปพร้อมทำงานแบบออฟไลน์แล้ว" หรือ "เนื้อหาเวอร์ชันใหม่พร้อมใช้งาน"
เราจะเรียกกรณีการใช้งานประเภทนี้ที่ Service Worker ไม่จำเป็นต้องได้รับข้อความจากหน้าเว็บเพื่อเริ่มการสื่อสารว่า "การประกาศการอัปเดต" ในคู่มือนี้ เราจะดูวิธีต่างๆ ในการใช้การสื่อสารประเภทนี้ระหว่างหน้าเว็บกับ Service Worker โดยใช้ API เบราว์เซอร์มาตรฐานและไลบรารี Workbox
กรณีการใช้งานจริง
Tinder
Tinder PWA ใช้ workbox-window
เพื่อฟังช่วงเวลาสําคัญในวงจรบริการของ Service Worker จากหน้าเว็บ ("ติดตั้ง" "ควบคุม" และ "เปิดใช้งาน") วิธีนี้จะช่วยให้ Service Worker ใหม่แสดงแบนเนอร์ "อัปเดตพร้อมใช้งาน" เมื่อเริ่มทํางาน เพื่อให้ผู้ใช้รีเฟรช PWA และเข้าถึงฟีเจอร์ล่าสุดได้
Squoosh
ใน Squoosh PWA เมื่อ Service Worker แคชชิ้นงานที่จำเป็นทั้งหมดเพื่อให้ทำงานแบบออฟไลน์ได้ ก็จะส่งข้อความไปยังหน้าเว็บเพื่อแสดงข้อความแจ้ง "พร้อมทำงานแบบออฟไลน์" เพื่อให้ผู้ใช้ทราบเกี่ยวกับฟีเจอร์นี้
การใช้ 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
มอบวิธีมาตรฐานในการแจ้งเตือนไคลเอ็นต์หน้าต่างว่ามีการอัปเดตคำตอบที่แคชไว้แล้ว ซึ่งมักใช้ร่วมกับกลยุทธ์ StaleWhileRevalidate
หากต้องการประกาศการอัปเดต ให้เพิ่ม 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 ต่อไปนี้เพื่อติดตั้งใช้งาน "การออกอากาศการอัปเดต"
Broadcast Channel 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 นี้ แต่บางเมธอดอาจไม่รองรับ โปรดตรวจสอบการรองรับเบราว์เซอร์ก่อนใช้งาน
ช่องทางของข้อความ
ช่องทางการรับส่งข้อความต้องใช้ขั้นตอนการกำหนดค่าเริ่มต้นด้วยการส่งพอร์ตจากหน้าเว็บไปยัง Service Worker เพื่อสร้างช่องทางการสื่อสารระหว่างหน้าเว็บกับ Service Worker หน้าเว็บสร้างอินสแตนซ์ของออบเจ็กต์ MessageChannel
และส่งพอร์ตไปยัง Service Worker ผ่านอินเทอร์เฟซ postMessage()
ดังนี้
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
};
Service Worker ได้รับพอร์ตและบันทึกการอ้างอิงถึงพอร์ตนั้น
// 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 ที่สําคัญ และการสื่อสารกับหน้าเว็บเกี่ยวกับการเปลี่ยนแปลงในเนื้อหาหรือข้อมูลที่แคชไว้ คุณอาจนึกถึง Use Case ที่น่าสนใจอื่นๆ ได้เมื่อ Service Worker สื่อสารกับหน้าเว็บอย่างสม่ำเสมอโดยที่ก่อนหน้านี้ไม่ได้รับการแจ้งเตือนใดๆ
สำหรับรูปแบบเพิ่มเติมของการสื่อสารของ Windows และ Service Worker โปรดดูที่
- คำแนะนำในการแคชล่วงหน้า: การเรียกใช้ Service Worker จากหน้าเว็บเพื่อแคชทรัพยากรล่วงหน้า (เช่น ในสถานการณ์การดึงข้อมูลล่วงหน้า)
- การสื่อสารแบบ 2 ทาง: การมอบหมายงานให้กับ Service Worker (เช่น การดาวน์โหลดขนาดใหญ่) และแจ้งข้อมูลความคืบหน้าให้หน้าเว็บทราบอยู่เสมอ