ในบางสถานการณ์ โปรแกรมทำงานของบริการอาจจำเป็นต้องสื่อสารเชิงรุกกับแท็บที่ใช้งานอยู่ที่ตัวควบคุมนี้ควบคุมเพื่อแจ้งเหตุการณ์บางอย่าง ตัวอย่างเช่น
- แจ้งให้หน้าเว็บทราบเมื่อติดตั้ง Service Worker เวอร์ชันใหม่แล้ว เพื่อให้หน้าเว็บแสดงปุ่ม "อัปเดตเพื่อรีเฟรช" แก่ผู้ใช้เพื่อเข้าถึงฟังก์ชันการทำงานใหม่ได้ทันที
- แจ้งให้ผู้ใช้ทราบถึงการเปลี่ยนแปลงในข้อมูลที่แคชไว้ที่เกิดขึ้นที่ฝั่ง Service Worker โดยการแสดงสัญญาณบอกสถานะ เช่น "แอปพร้อมทำงานแบบออฟไลน์แล้ว" หรือ "มีเนื้อหาเวอร์ชันใหม่พร้อมใช้งาน"
![แผนภาพแสดง Service Worker ที่กำลังสื่อสารกับหน้าเว็บเพื่อส่งข้อมูลอัปเดต](https://web.dev/static/articles/broadcast-updates-guide/image/diagram-showing-service-25fb181d9fd41.png?authuser=6&hl=th)
เราจะเรียกกรณีการใช้งานประเภทนี้ที่โปรแกรมทำงานของบริการไม่จำเป็นต้องได้รับข้อความจากหน้าเว็บเพื่อเริ่มการสื่อสารว่า "การอัปเดตจากประกาศ" ในคู่มือนี้ เราจะพูดถึงวิธีต่างๆ ในการใช้การสื่อสารประเภทนี้ระหว่างหน้าเว็บและ Service Worker โดยใช้ API เบราว์เซอร์มาตรฐานและไลบรารี Workbox
กรณีการผลิต
Tinder
Tinder PWA ใช้ workbox-window
เพื่อฟังช่วงเวลาของวงจรการทำงานของ Service Worker ที่สำคัญจากหน้าเว็บ ("ติดตั้ง" "ควบคุมแล้ว" และ "เปิดใช้งานแล้ว") เมื่อมี Service Worker ใหม่เข้ามาใช้งาน แบนเนอร์ "มีอัปเดต" จะแสดงขึ้นมาเพื่อให้รีเฟรช PWA และเข้าถึงฟีเจอร์ล่าสุดได้ ดังนี้
![ภาพหน้าจอของฟังก์ชัน "มีการอัปเดต" ของเว็บแอป Tinder](https://web.dev/static/articles/broadcast-updates-guide/image/a-screenshot-tinders-we-7235223308143.png?authuser=6&hl=th)
สควอช
ใน Squoosh PWA เมื่อ Service Worker แคชเนื้อหาที่จำเป็นทั้งหมดเพื่อให้ทำงานแบบออฟไลน์ได้ จะมีการส่งข้อความไปยังหน้าเว็บเพื่อแสดงข้อความโทสต์ "พร้อมทำงานแบบออฟไลน์" เพื่อแจ้งให้ผู้ใช้ทราบเกี่ยวกับฟีเจอร์นี้
![ภาพหน้าจอของฟังก์ชัน "พร้อมทำงานแบบออฟไลน์" ของเว็บแอป Squoosh](https://web.dev/static/articles/broadcast-updates-guide/image/a-screenshot-squoosh-web-f8bcc1343566b.png?authuser=6&hl=th)
การใช้ Workbox
ฟังเหตุการณ์วงจรชีวิตของโปรแกรมทำงานของบริการ
workbox-window
มีอินเทอร์เฟซที่ตรงไปตรงมาในการฟังเหตุการณ์สำคัญในวงจรการทำงานของ Service Worker
เบื้องหลัง ไลบรารีจะใช้ API ฝั่งไคลเอ็นต์ เช่น updatefound
และ statechange และมี Listener เหตุการณ์ในระดับที่สูงกว่าในออบเจ็กต์ 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
เป็นวิธีมาตรฐานในการแจ้งเตือนไคลเอ็นต์หน้าต่างว่ามีการอัปเดตการตอบกลับที่แคชไว้ วิธีนี้ใช้กันมากที่สุดร่วมกับกลยุทธ์ Staleส่งข้อมูลที่เกี่ยวข้อง
หากต้องการเผยแพร่การอัปเดต ให้เพิ่ม 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 ช่องการออกอากาศ
โปรแกรมทำงานของบริการจะสร้างออบเจ็กต์ 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
ใช้รหัสโปรแกรมทำงานของบริการต่อไปนี้เพื่อส่งข้อความไปยังแท็บที่โฟกัสล่าสุด
// 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
}
};
API ของไคลเอ็นต์เป็นตัวเลือกที่ยอดเยี่ยมสําหรับกรณีต่างๆ เช่น การประกาศข้อมูลไปยังแท็บที่ใช้งานอยู่หลายแท็บ API ได้รับการรองรับจากเบราว์เซอร์หลักๆ ทั้งหมด แต่จะมีบางวิธีที่ไม่รองรับ โปรดตรวจสอบการสนับสนุน ของเบราว์เซอร์ก่อนใช้งาน
ช่องทางของข้อความ
ช่องทางข้อความต้องมีขั้นตอนการกำหนดค่าเริ่มต้นโดยส่งพอร์ตจากหน้าไปยัง Service Worker เพื่อสร้างช่องทางการสื่อสารระหว่าง 2 ช่องทางนี้ หน้านี้สร้างอินสแตนซ์ 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
};
โปรแกรมทำงานของบริการจะได้รับพอร์ตและบันทึกการอ้างอิงไปยังพอร์ตดังกล่าว ดังนี้
// 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 to Service Worker อย่างหนึ่ง นั่นคือ "การอัปเดตจากประกาศ" ตัวอย่างที่สำรวจ ได้แก่ การรับฟังเหตุการณ์สำคัญในวงจรการทำงานของ Service Worker และการสื่อสารกับหน้าเว็บเกี่ยวกับการเปลี่ยนแปลงของเนื้อหาหรือข้อมูลที่แคชไว้ ให้ลองนึกภาพกรณีการใช้งานที่น่าสนใจมากขึ้น ซึ่งโปรแกรมทำงานของบริการโต้ตอบกับหน้าเว็บในเชิงรุกโดยไม่เคยได้รับข้อความใดเลย
โปรดดูรูปแบบเพิ่มเติมสำหรับการสื่อสารกับ Windows และ Service Worker ที่
- คำแนะนำในการแคชที่จำเป็น: การเรียกใช้ Service Worker จากหน้าเว็บเพื่อแคชทรัพยากรล่วงหน้า (เช่น ในสถานการณ์การดึงข้อมูลล่วงหน้า)
- การสื่อสารแบบ 2 ทาง: การมอบหมายงานให้กับ Service Worker (เช่น การดาวน์โหลดจำนวนมาก) และการแจ้งความคืบหน้าในหน้าเว็บ