במקרים מסוימים, ייתכן שאפליקציית אינטרנט תצטרך ליצור ערוץ תקשורת דו-כיווני בין ול-Service Worker.
לדוגמה: בפודקאסט PWA, אפשר לפתח תכונה שתאפשר למשתמש להוריד פרקים של לצריכה אופליין ומאפשרים ב-service worker כדי לעדכן את הדף באופן קבוע לגבי ההתקדמות, לכן thread יכול לעדכן את ממשק המשתמש.
במדריך הזה נבחן את הדרכים השונות להטמעת תקשורת דו-כיוונית בין אנשים החלון והשירות של עובדים, באמצעות ממשקי API שונים, ספריית תיבת העבודה, וגם במקרים מתקדמים מסוימים.
שימוש בתיבת העבודה
workbox-window
היא קבוצה של
של ספריית תיבות העבודה
לפעול בהקשר של החלון. Workbox
המחלקה מספקת שיטת messageSW()
לשליחת הודעה ל-Service Worker הרשום של המכונה.
ממתינים לתגובה.
קוד הדף הבא יוצר מכונת Workbox
חדשה ושולח הודעה ל-Service Worker
כדי לקבל את הגרסה שלו:
const wb = new Workbox('/sw.js');
wb.register();
const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);
ה-Service Worker מטמיע אוזן הודעה בצד השני ומגיב Service Worker:
const SW_VERSION = '1.0.0';
self.addEventListener('message', (event) => {
if (event.data.type === 'GET_VERSION') {
event.ports[0].postMessage(SW_VERSION);
}
});
מאחורי הקלעים, הספרייה משתמשת בממשק API של הדפדפן, שנבדוק בקטע הבא: הודעה ערוץ, אבל הרבה מהם מופשטים פרטי ההטמעה, ומקלים על השימוש, תוך שימוש בדפדפן הרחב תמיכה יש ב-API הזה.
שימוש בממשקי API של דפדפן
אם ספריית Workbox לא מתאימה לצרכים שלכם, יש כמה ממשקי API ברמה נמוכה יותר שזמינים עבור להטמיע תקשורת דו-כיוונית בין דפים לבין Service Worker. יש כמה דמיון והבדלים:
נקודות דמיון:
- בכל המקרים התקשורת מתחילה בצד אחד דרך הממשק של
postMessage()
ומקבלת בצד השני, מטמיעים handler שלmessage
. - בפועל, כל ממשקי ה-API הזמינים מאפשרים לנו ליישם את אותם תרחישים לדוגמה, אבל חלקם. עשוי לפשט את הפיתוח בתרחישים מסוימים.
הבדלים:
- יש להם דרכים שונות לזהות את הצד השני של התקשורת: חלקם משתמשים התייחסות מפורשת להקשר השני, בעוד שאחרים יכולים לתקשר באופן מרומז באמצעות שרת proxy שבו נוצר מופע של אובייקט בכל צד.
- התמיכה בדפדפן משתנה בין היתר.
ממשק API של ערוץ שידור
Broadcast Channel API מאפשר תקשורת בסיסית בין הקשרי גלישה באמצעות BroadcastChannel אובייקטים.
כדי להטמיע אותו, קודם כל הקשר צריך ליצור אובייקט BroadcastChannel
עם אותו מזהה
ולשלוח ולקבל הודעות ממנו:
const broadcast = new BroadcastChannel('channel-123');
האובייקט BroadcastChannel חושף ממשק postMessage()
לשליחת הודעה לכל האזנה
הקשר:
//send message
broadcast.postMessage({ type: 'MSG_ID', });
בכל הקשר בדפדפן יש אפשרות להאזין להודעות באמצעות השיטה onmessage
של BroadcastChannel
object:
//listen to messages
broadcast.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//process message...
}
};
כפי שנראה, אין התייחסות מפורשת להקשר מסוים, ולכן אין צורך לקבל להתייחס קודם ל-Service Worker או לכל לקוח מסוים.
החיסרון הוא שכרגע יש ב-API תמיכה מ-Chrome, Firefox ו-Edge, אבל דפדפנים אחרים, כמו Safari, לא תומכים בו עדיין.
API של לקוח
Client API מאפשר לקבל
התייחסות לכל האובייקטים WindowClient
שמייצגים את הכרטיסיות הפעילות שבשליטת Service Worker.
מכיוון שהדף נשלט על ידי קובץ שירות (service worker) יחיד, הוא מאזין להודעות ושולח אותן
קובץ שירות (service worker) פעיל ישירות דרך הממשק של serviceWorker
:
//send message
navigator.serviceWorker.controller.postMessage({
type: 'MSG_ID',
});
//listen to messages
navigator.serviceWorker.onmessage = (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//process response
}
};
באופן דומה, Service Worker מאזין להודעות על ידי הטמעת אוזן onmessage
:
//listen to messages
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'MSG_ID') {
//Process message
}
});
כדי לתקשר עם לקוחות כלשהם, Service Worker מקבל מערך של
WindowClient
אובייקטים על ידי הרצת
שיטות כמו
Clients.matchAll()
והקבוצה
Clients.get()
. לאחר מכן היא תוכל
postMessage()
אחד מהם:
//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'});
}
});
Client API
הוא אפשרות טובה לתקשר בקלות עם כל הכרטיסיות הפעילות של קובץ שירות (service worker)
בצורה פשוטה יחסית. ממשק API נתמך על ידי כל
דפדפנים,
אבל לא כל השיטות עשויות להיות זמינות, לכן חשוב לבדוק את התמיכה של הדפדפן לפני
להטמיע אותו באתר.
ערוץ הודעות
לערוץ הודעות נדרש הגדרה והעברה של יציאה מהקשר אחד לאחר כדי ליצור תקשורת דו-כיוונית .
כדי לאתחל את הערוץ, הדף יוצר אובייקט MessageChannel
ומשתמש בו
כדי לשלוח יציאה ל-Service Worker הרשום. הדף מטמיע גם האזנה ל-onmessage
ב-
כדי לקבל הודעות מההקשר השני:
const messageChannel = new MessageChannel();
//Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
messageChannel.port2,
]);
//Listen to messages
messageChannel.port1.onmessage = (event) => {
// Process message
};
קובץ השירות מקבל את היציאה, שומר הפניה אליה ומשתמש בה כדי לשלוח הודעה לאחר צד:
let communicationPort;
//Save reference to port
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'PORT_INITIALIZATION') {
communicationPort = event.ports[0];
}
});
//Send messages
communicationPort.postMessage({type: 'MSG_ID'});
בשלב הזה, MessageChannel
נתמך על ידי כל השירותים העיקריים
דפדפנים.
ממשקי API מתקדמים: סנכרון ברקע ואחזור ברקע
במדריך הזה בחנו דרכים ליישום טכניקות תקשורת דו-כיווניות, במקרים פשוטים, כמו העברת הודעת מחרוזת שמתארת את הפעולה שצריך לבצע, או רשימה של כתובות URL לשמירה במטמון מהקשר אחד לאחר. בחלק זה נבחן שני ממשקי API שמשמשים לטיפול תרחישים: היעדר קישוריות והורדות ארוכות.
סנכרון ברקע
אפליקציית צ'אט עשויה לרצות לוודא שההודעות לעולם לא יאבדו בגלל קישוריות לא טובה. Background Sync API מאפשר לך דחיית פעולות שיש לנסות שוב כאשר למשתמש יש קישוריות יציבה. האפשרות הזאת שימושית כדי לוודא כל מה שהמשתמש רוצה לשלוח, למעשה נשלח.
במקום הממשק postMessage()
, הדף רושם sync
:
navigator.serviceWorker.ready.then(function (swRegistration) {
return swRegistration.sync.register('myFirstSync');
});
לאחר מכן, קובץ השירות (service worker) מאזין לאירוע sync
כדי לעבד את ההודעה:
self.addEventListener('sync', function (event) {
if (event.tag == 'myFirstSync') {
event.waitUntil(doSomeStuff());
}
});
הפונקציה doSomeStuff()
צריכה להחזיר הבטחה שמציינת הצלחה או כישלון
שאתם מנסים לעשות. אם היא הושלמה, הסנכרון הסתיים. אם הפעולה תיכשל, יתוזמן סנכרון נוסף
לנסות שוב. סנכרונים חוזרים גם ממתינים לקישוריות ומפעילים השהיה מעריכית לפני ניסיון חוזר (exponential backoff).
לאחר ביצוע הפעולה, ה-Service Worker יכול לתקשר עם הדף כדי לעדכן את ממשק המשתמש באמצעות כל אחד מממשקי ה-API לתקשורת שפורטו למעלה.
חיפוש Google משתמש בסנכרון ברקע כדי לשמור שאילתות שנכשלו עקב קישוריות לא טובה, ולנסות שוב מאוחר יותר כשהמשתמש יהיה מחובר. לאחר ביצוע הפעולה, התוצאה מועברת המשתמש באמצעות התראה באינטרנט:
אחזור ברקע
עבור קטעי עבודה קצרים יחסית כמו שליחת הודעה או רשימה של כתובות URL לשמירה, האפשרויות שחקרנו עד עכשיו הן בחירה טובה. אם המשימה נמשכת יותר מדי זמן, הדפדפן יכבה את השירות עובד, אחרת הדבר מהווה סיכון לפרטיות ולסוללה של המשתמש.
ה-API לאחזור ברקע מאפשר להסיר לעובד שירות (service worker) משימה ארוכה, כמו הורדת סרטים, פודקאסטים או רמות של משחק.
כדי לתקשר עם קובץ השירות (service worker) שבדף, יש להשתמש ב-backgroundFetch.fetch
, במקום ב
postMessage()
:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.fetch(
'my-fetch',
['/ep-5.mp3', 'ep-5-artwork.jpg'],
{
title: 'Episode 5: Interesting things.',
icons: [
{
sizes: '300x300',
src: '/ep-5-icon.png',
type: 'image/png',
},
],
downloadTotal: 60 * 1024 * 1024,
},
);
});
האובייקט BackgroundFetchRegistration
מאפשר לדף האזנה לאירוע progress
אחרי המעקב
התקדמות ההורדה:
bgFetch.addEventListener('progress', () => {
// If we didn't provide a total, we can't provide a %.
if (!bgFetch.downloadTotal) return;
const percent = Math.round(
(bgFetch.downloaded / bgFetch.downloadTotal) * 100,
);
console.log(`Download progress: ${percent}%`);
});
השלבים הבאים
במדריך הזה חקרנו את המקרה הכללי ביותר של תקשורת בין דפים ל-Service Workers (תקשורת דו-כיוונית).
במקרים רבים, ייתכן שיהיה צורך בהקשר אחד בלבד כדי לתקשר עם השני, בלי לקבל תשובה. עיינו במדריכים הבאים לקבלת הדרכה על הטמעה של טכניקות חד-כיווניות את הדפים שלכם מ-Service worker ואליהם, יחד עם תרחישים לדוגמה ודוגמאות ייצור:
- מדריך שמירת נתונים במטמון: שליחת קריאה לעובדי שירות מהדף כדי לשמור משאבים במטמון מראש (למשל, בתרחישים של שליפה מראש).
- עדכוני שידור: התקשרות לדף מ-Service Worker כדי ליידע את המשתמשים על עדכונים חשובים (למשל, יש גרסה חדשה של אפליקציית האינטרנט).