בתרחישים מסוימים, יכול להיות ש-Service Worker יצטרך לתקשר באופן יזום עם כל אחת מהכרטיסיות הפעילות שבשליטתו כדי להודיע על אירוע מסוים. דוגמאות:
- עדכון הדף על התקנת גרסה חדשה של Service Worker, כדי שהמשתמש יוכל להציג בדף לחצן Update to Refresh כדי לקבל גישה מיידית לפונקציונליות החדשה.
- להודיע למשתמש על שינוי בנתונים ששמורים במטמון שהתרחש בצד של ה-service worker, על ידי הצגת אינדיקציה, כמו: "האפליקציה מוכנה עכשיו לעבודה אופליין" או "יש גרסה חדשה של התוכן".
נתייחס לתרחישים לדוגמה שבהם שירות ה-worker לא צריך לקבל הודעה מהדף כדי להתחיל תקשורת בתור 'עדכונים לשידור'. במדריך הזה נציג דרכים שונות להטמעת סוג התקשורת הזה בין דפים ל-Service Workers, באמצעות ממשקי API רגילים של הדפדפן וספריית Workbox.
בקשות תמיכה בסביבת ייצור
Tinder
אפליקציית Tinder ל-PWA משתמשת ב-workbox-window
כדי להאזין לדפים לרגעים חשובים במחזור החיים של ה-service worker ('התקנה', 'שליטה' ו'הפעלה'). כך, כש-Service Worker חדש נכנס לפעולה, מוצג באנר עם "עדכון זמין", כדי שהוא יוכל לרענן את ה-PWA ולגשת לתכונות העדכניות:
סקווש
ב-Squoosh PWA, כשעובד השירות שומר במטמון את כל הנכסים הנחוצים כדי שהאפליקציה תפעל במצב אופליין, הוא שולח הודעה לדף כדי להציג הודעה קופצת עם הכיתוב 'מוכן לעבודה במצב אופליין', כדי להודיע למשתמש על התכונה:
שימוש בתיבת העבודה
האזנה לאירועים במחזור החיים של שירות ה-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
לאפשרויות האסטרטגיה בצד של קובץ השירות:
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
קובץ השירות יוצר אובייקט BroadcastChannel ומתחיל לשלוח אליו הודעות. כל הקשר (למשל דף) שרוצה לקבל את ההודעות האלה יכול ליצור אובייקט BroadcastChannel
ולהטמיע בורר הודעות כדי לקבל הודעות.
כדי להודיע לדף כשמתקין שירות עבודה חדש, משתמשים בקוד הבא:
// 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 הזה.
Client 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'});
}
});
הדף מטמיע handler של הודעות כדי ליירט את ההודעות האלה:
// Listen to messages
navigator.serviceWorker.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
// Process response
}
};
ממשק ה-API ללקוח הוא פתרון מצוין למקרים כמו שידור מידע לכמה כרטיסיות פעילות. ה-API נתמך על ידי כל הדפדפנים המובילים, אבל לא כל השיטות שלו נתמכות. לפני השימוש, כדאי לבדוק את תמיכת הדפדפן.
ערוץ הודעות
בשביל Message Channel צריך לבצע שלב הגדרה ראשוני, באמצעות העברת יציאה מהדף ל-Service Worker, כדי ליצור ערוץ תקשורת ביניהם. הדף יוצר מופע של אובייקט MessageChannel
ומעביר יציאה לקובץ השירות דרך הממשק 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 לבין שירות העבודה: 'שידור עדכונים'. הדוגמאות כוללות האזנה לאירועים חשובים במחזור החיים של קובצי שירות (service worker) ודיווח על שינויים בתוכן או בנתונים שנשמרו במטמון. אפשר לחשוב על תרחישי שימוש מעניינים יותר שבהם עובד השירות מתקשר באופן יזום עם הדף, בלי לקבל הודעה מראש.
דפוסים נוספים של תקשורת בין חלון לבין עובד שירות זמינים במאמרים הבאים:
- מדריך לשימוש חובה במטמון: קריאה לקובץ שירות (service worker) מהדף כדי לשמור משאבים במטמון מראש (למשל בתרחישים של אחסון מקדים).
- תקשורת דו-כיוונית: הענקת גישה למשימה לעובד שירות (למשל, הורדה כבדה) ועדכון הדף לגבי ההתקדמות.