חלון תיבת עבודה

החבילה workbox-window היא קבוצה של מודולים שמיועדים לפעול בהקשר של window, כלומר בתוך דפי האינטרנט. הן השלמה לחבילות האחרות של ארגזי עבודה שפועלות ב-Service Worker.

התכונות/המטרות העיקריות של workbox-window הן:

ייבוא ושימוש בתיבת העבודה-חלון

נקודת הכניסה הראשית לחבילת workbox-window היא המחלקה Workbox, וניתן לייבא אותה לקוד מה-CDN שלנו או באמצעות כל אחד מהכלים הפופולריים ליצירת חבילות של JavaScript.

שימוש ב-CDN שלנו

הדרך הקלה ביותר לייבא את המחלקה Workbox לאתר שלכם היא דרך רשת ה-CDN שלנו:

<script type="module">
  import {Workbox} from 'https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-window.prod.mjs';

  if ('serviceWorker' in navigator) {
    const wb = new Workbox('/sw.js');

    wb.register();
  }
</script>

שימו לב שבדוגמה הזו נעשה שימוש ב<script type="module"> ובהצהרה import כדי לטעון את המחלקה Workbox. אומנם נראה לכם שתצטרכו להמיר את הקוד הזה כדי שהוא יפעל בדפדפנים ישנים יותר, אבל למעשה זה לא הכרחי.

כל הדפדפנים הנפוצים ביותר שתומכים ב-service worker גם תומכים במודולים של JavaScript מקוריים, כך שמתאים לגמרי להציג את הקוד הזה בכל דפדפן (דפדפנים ישנים יותר פשוט יתעלמו ממנו).

מתבצעת טעינה של תיבת העבודה עם חבילות JavaScript

אמנם לא נדרש שום כלי כדי להשתמש ב-workbox-window, אבל אם תשתית הפיתוח שלכם כבר כוללת Bundler כמו webpack או Rollup שעובדים עם יחסי תלות של npm, אפשר להשתמש בהם כדי לטעון את workbox-window.

השלב הראשון הוא להתקין את workbox-window בהתאם לאפליקציה שלכם:

npm install workbox-window

לאחר מכן, באחד מקובצי ה-JavaScript של האפליקציה, תיבת העבודה import על ידי הפניה לשם החבילה workbox-window:

import {Workbox} from 'workbox-window';

if ('serviceWorker' in navigator) {
  const wb = new Workbox('/sw.js');

  wb.register();
}

אם ה-bundler תומך בפיצול קוד באמצעות הצהרות ייבוא דינמי, אפשר גם לטעון באופן מותנה את workbox-window, וכך להקטין את גודל החבילה הראשית בדף.

על אף ש-workbox-window קטן למדי, אין צורך לטעון אותו עם הלוגיקה העיקרית של האפליקציה של האתר שלכם, מכיוון ש-Service Workers, מטבעם, הם שיפור הדרגתי.

if ('serviceWorker' in navigator) {
  const {Workbox} = await import('workbox-window');

  const wb = new Workbox('/sw.js');
  wb.register();
}

מושגי קיבוץ מתקדמים

בניגוד לחבילות Workbox שפועלות ב-Service Worker, קובצי ה-build עם השדות main ו-module ב-package.json מועברים ל-ES5.workbox-window כך הם תואמים לכלי ה-build של ימינו – חלקם לא מאפשרים למפתחים להעביר כל דבר מהתלות שלהם ב-node_module.

אם מערכת ה-build מאפשרת להעביר את יחסי התלות (או אם אתם לא צריכים להמיר את הקוד לאף אחד), עדיף לייבא קובץ מקור ספציפי ולא את החבילה עצמה.

הנה הדרכים השונות לייבא את Workbox, יחד עם הסבר על מה שכל אחד מהם יחזיר:

// Imports a UMD version with ES5 syntax
// (pkg.main: "build/workbox-window.prod.umd.js")
const {Workbox} = require('workbox-window');

// Imports the module version with ES5 syntax
// (pkg.module: "build/workbox-window.prod.es5.mjs")
import {Workbox} from 'workbox-window';

// Imports the module source file with ES2015+ syntax
import {Workbox} from 'workbox-window/Workbox.mjs';

דוגמאות

אחרי שמייבאים את המחלקה Workbox, אפשר להשתמש בה כדי לרשום את קובץ השירות (service worker) ולתקשר איתו. הנה כמה דוגמאות לדרכים שבהן תוכלו להשתמש ב-Workbox באפליקציה:

רישום קובץ שירות (service worker) והתראה למשתמש בפעם הראשונה ש-Service Worker פעיל

קובצי שירות רבים של אפליקציות אינטרנט, ששומרים מראש נכסים דיגיטליים, מפעילים מטמון כך שהאפליקציה תפעל אופליין בטעינות הבאות של הדפים. במקרים מסוימים כדאי ליידע את המשתמש שהאפליקציה זמינה עכשיו במצב אופליין.

const wb = new Workbox('/sw.js');

wb.addEventListener('activated', event => {
  // `event.isUpdate` will be true if another version of the service
  // worker was controlling the page when this version was registered.
  if (!event.isUpdate) {
    console.log('Service worker activated for the first time!');

    // If your service worker is configured to precache assets, those
    // assets should all be available now.
  }
});

// Register the service worker after event listeners have been added.
wb.register();

הודעה למשתמש אם Service Worker הותקן אך נתקע וממתין להפעלה

כאשר דף הנשלט על ידי Service Worker קיים רושם worker חדש כברירת מחדל, ה-Service Worker לא יופעל עד שכל הלקוחות שבשליטת ה-Service Worker הראשוני פורקים באופן מלא.

זהו מקור נפוץ לבלבול אצל מפתחים, במיוחד במקרים שבהם טעינה מחדש של הדף הנוכחי לא גורמת להפעלה של Service Worker.

כדי למנוע בלבול ולהבהיר מתי המצב הזה מתרחש, המחלקה Workbox מספקת אירוע waiting שאפשר להאזין לו:

const wb = new Workbox('/sw.js');

wb.addEventListener('waiting', event => {
  console.log(
    `A new service worker has installed, but it can't activate` +
      `until all tabs running the current version have fully unloaded.`
  );
});

// Register the service worker after event listeners have been added.
wb.register();

שליחת הודעה למשתמש על עדכוני מטמון מחבילת workbox-broadcast-update

חבילת workbox-broadcast-update היא דרך מצוינת להציג תוכן מהמטמון (לשליחה מהירה), וגם לעדכן את המשתמשים לגבי עדכונים לתוכן הזה (באמצעות אסטרטגיית 'לא פעיל בזמן אימות מחדש').

כדי לקבל את העדכונים האלה מהחלון, אפשר להאזין לאירועי message מסוג CACHE_UPDATED:

const wb = new Workbox('/sw.js');

wb.addEventListener('message', event => {
  if (event.data.type === 'CACHE_UPDATED') {
    const {updatedURL} = event.data.payload;

    console.log(`A newer version of ${updatedURL} is available!`);
  }
});

// Register the service worker after event listeners have been added.
wb.register();

שליחת רשימה של כתובות URL למטמון ל-Service Worker

באפליקציות מסוימות יש אפשרות להכיר את כל הנכסים שצריך לשמור מראש במטמון בזמן ה-build, אבל אפליקציות מסוימות מציגות דפים שונים לגמרי, בהתאם לכתובת ה-URL שאליה המשתמש מגיע.

עבור אפליקציות בקטגוריה השנייה, כדאי לשמור במטמון רק את הנכסים שהמשתמש צריך עבור הדף הספציפי שבו ביקר. כשמשתמשים בחבילת workbox-routing, אפשר לשלוח לנתב רשימה של כתובות URL לשמירה במטמון, והוא שומר את כתובות ה-URL האלה במטמון בהתאם לכללים שהוגדרו בנתב עצמו.

בדוגמה הזו נשלחת רשימה של כתובות URL שנטענו על ידי הדף לנתב בכל פעם שמופעל קובץ שירות (service worker) חדש. הערה: אין בעיה לשלוח את כל כתובות ה-URL כי רק כתובות ה-URL שתואמות לנתיב מוגדר ב-Service Worker יישמרו במטמון:

const wb = new Workbox('/sw.js');

wb.addEventListener('activated', event => {
  // Get the current page URL + all resources the page loaded.
  const urlsToCache = [
    location.href,
    ...performance.getEntriesByType('resource').map(r => r.name),
  ];
  // Send that list of URLs to your router in the service worker.
  wb.messageSW({
    type: 'CACHE_URLS',
    payload: {urlsToCache},
  });
});

// Register the service worker after event listeners have been added.
wb.register();

רגעים חשובים במחזור החיים של Service Worker

מחזור החיים של Service Worker הוא מורכב ויכול להיות שתתקשו להבין אותו במלואו. חלק מהסיבה לכך היא שה-Service Worker חייב לטפל בכל מקרי הקצה של כל שימושים אפשריים ב-Service Worker (למשל, רישום של יותר מ-Service worker אחד, רישום של משתני שירות (service worker) שונים במסגרות שונות, רישום של Service worker עם שמות שונים וכו'.

אבל רוב המפתחים שמטמיעים את Service Worker לא צריכים לדאוג לגבי כל התרחישים האלה, כי השימוש בהם די פשוט. רוב המפתחים רושמים רק קובץ שירות (service worker) אחד לכל טעינת דף, והם לא משנים את השם של קובץ השירות (service worker) שהם פורסים בשרת.

המחלקה Workbox מאמצת את התצוגה הפשוטה הזו של מחזור החיים של Service Worker על ידי חלוקה של כל רישומי ה-Service Worker לשתי קטגוריות: הבעלים של המכונה, קובץ השירות הרשום וקובץ השירות החיצוני:

  • קובץ שירות (service worker) רשום: קובץ שירות (service worker) שהתחיל להתקין כתוצאה מהמכונה של Workbox שקוראת ל-register() או ל-service worker של register(), אם הקריאה ל-register() לא הפעילה אירוע של updatefound ברישום.
  • Service Worker חיצוני: קובץ שירות (service worker) שהתחיל להתקין בנפרד מהמכונה Workbox שקוראת ל-register(). בדרך כלל זה קורה כשלמשתמש יש גרסה חדשה של האתר שפתוחה בכרטיסייה אחרת. כשאירוע מגיע מ-service worker חיצוני, המאפיין isExternal של האירוע מוגדר ל-true.

מתוך התחשבות בשני הסוגים האלה של Service workers, מוצג פירוט של כל הרגעים החשובים במחזור החיים של ה-Service Worker, יחד עם המלצות למפתחים איך לטפל בהם:

בפעם הראשונה ש-Service Worker מותקן

סביר להניח שתרצו להתייחס לפעם הראשונה שבה קובץ שירות (service worker) מתקינים באופן שונה מהאופן שבו אתם מטפלים בכל העדכונים העתידיים.

ב-workbox-window אפשר להבחין בין ההתקנה הראשונה של הגרסה לבין עדכונים עתידיים על ידי בדיקת המאפיין isUpdate בכל אחד מהאירועים הבאים. בהתקנה הראשונה, isUpdate יהיה false.

const wb = new Workbox('/sw.js');

wb.addEventListener('installed', event => {
  if (!event.isUpdate) {
    // First-installed code goes here...
  }
});

wb.register();
ערך אירוע הפעולה המומלצת
הותקן קובץ שירות (service worker) חדש (בפעם הראשונה) installed

בפעם הראשונה שבה קובץ שירות (service worker) מתקין, בדרך כלל מקובל לשמור מראש את כל הנכסים שנדרשים כדי שהאתר יפעל במצב אופליין. כדאי להודיע למשתמש שהאתר שלו יכול לפעול עכשיו במצב אופליין.

בנוסף, מכיוון שההתקנה הראשונה של קובץ שירות (service worker) לא תיווצר אירועי אחזור של טעינת הדף הזו, כדאי גם לשמור במטמון נכסים שכבר נטענו (אבל אין צורך לעשות זאת אם הנכסים האלה כבר שמורים מראש). בדוגמה שלמעלה, שלח ל-Service Worker רשימה של כתובות URL למטמון מראה איך לעשות את זה.

קובץ השירות (service worker) התחיל לשלוט בדף controlling

אחרי שהתקנתם קובץ שירות (service worker) חדש ומתחיל לשלוט בדף, כל אירועי האחזור הבאים יעברו דרך אותו קובץ שירות (service worker). אם קובץ השירות (service worker) מוסיף לוגיקה מיוחדת לטיפול באירוע אחזור מסוים, זו הנקודה שבה תדעו שהלוגיקה תפעל.

שימו לב שבפעם הראשונה שמתקינים קובץ שירות (service worker) הוא לא יתחיל לשלוט בדף הנוכחי, אלא אם הוא יתקשר למספר clients.claim() באירוע ההפעלה שלו. כברירת מחדל, צריך להמתין עד לטעינת הדף הבאה כדי להתחיל לשלוט.

מבחינת workbox-window, המשמעות היא שהאירוע controlling נשלח רק במקרים שבהם קובץ השירות (service worker) מבצע קריאה ל-clients.claim(). האירוע הזה לא יישלח אם הדף כבר נשלט לפני הרישום.

קובץ השירות (service worker) סיים להפעיל activated

כפי שצוין למעלה, בפעם הראשונה שבה קובץ שירות (service worker) מסיים להפעיל אותו, יכול להיות שהוא התחיל לשלוט בדף (או לא).

לכן, לא כדאי להאזין לאירוע ההפעלה כדי לדעת מתי ה-Service Worker שולט בדף. עם זאת, אם מפעילים לוגיקה באירוע הפעיל (ב-Service Worker) וצריך לדעת מתי הלוגיקה תושלם, האירוע שמופעל יידע על כך.

כשנמצאת גרסה מעודכנת של ה-Service Worker

כשמתבצעת התקנה של קובץ שירות (service worker) חדש אבל יש גרסה קיימת שכבר שולטת בדף, המאפיין isUpdate של כל האירועים הבאים יהיה true.

התגובה שלכם במצב הזה שונה בדרך כלל מההתקנה הראשונה, כי עליכם להחליט מתי ואיך המשתמש יקבל את העדכון.

ערך אירוע הפעולה המומלצת
הותקן קובץ שירות (service worker) חדש (מעדכן קובץ קודם) installed

אם זו לא ההתקנה הראשונה של קובץ ה-Service Worker (event.isUpdate === true), סימן שנמצאה והותקנה גרסה חדשה יותר של ה-Service Worker (כלומר, גרסה שונה מזו ששולטת כרגע בדף).

בדרך כלל המשמעות היא שגרסה חדשה יותר של האתר נפרסה בשרת שלך, ויכול להיות שהיצירה המקדימה של הנכסים החדשים הסתיימה.

הערה: חלק מהמפתחים משתמשים באירוע installed כדי ליידע את המשתמשים שיש גרסה חדשה של האתר שלהם. עם זאת, בהתאם לקריאה ל- skipWaiting() ב-service worker של ההתקנה, ייתכן שה-Service Worker המותקן לא יופעל מיד. אם מתקשרים אל skipWaiting(), מומלץ להודיע למשתמשים על העדכון ברגע שה-Service Worker החדש יופעל. אם לא מתקשרים אל skipWaiting, עדיף להודיע להם על העדכון שנמצא בהמתנה באירוע ההמתנה (פרטים נוספים בהמשך).

קובץ שירות (service worker) הותקן אך הוא נתקע בשלב ההמתנה waiting

אם הגרסה המעודכנת של קובץ השירות (service worker) לא תבצע קריאה אל skipWaiting() בזמן ההתקנה, היא לא תופעל עד שכל הדפים שנשלטים על ידי ה-Service Worker הפעיל הנוכחי ייטענו. כדאי ליידע את המשתמש שיש עדכון זמין והוא יוחל בביקור הבא שלו.

אזהרה! פעמים רבות מפתחים מבקשים מהמשתמשים לטעון מחדש כדי לקבל את העדכון, אבל במקרים רבים רענון הדף לא יפעיל את ה-worker המותקן. אם המשתמש ירענן את הדף וה-Service Worker עדיין ממתין, האירוע waiting יופעל שוב והמאפיין event.wasWaitingBeforeRegister מתקיים. הערה: אנחנו מתכננים לשפר את החוויה הזו בגרסה עתידית. יש לפעול לפי בעיה מס' 1848 לקבלת עדכונים.

אפשרות אחרת היא לשלוח למשתמש הודעה ולשאול אם הוא רוצה לקבל את העדכון או להמשיך להמתין. אם בוחרים לקבל את העדכון, אפשר להשתמש ב-postMessage() כדי להורות ל-Service Worker להריץ את skipWaiting(). כדי לראות דוגמה לכך, אפשר לעיין במתכון המתקדם לטעינת דף למשתמשים.

קובץ השירות (service worker) התחיל לשלוט בדף controlling

כשקובץ שירות (service worker) מעודכן מתחיל לשלוט בדף, המשמעות היא שהגרסה של ה-Service Worker שבה אתם שולטים כרגע שונה מהגרסה שהייתה בשליטה בזמן טעינת הדף. במקרים מסוימים, ייתכן שזה תקין, אבל ייתכן גם שחלק מהנכסים שאליהם הדף הנוכחי מפנה, כבר לא נמצאים במטמון (ואולי גם לא נמצאים בשרת). כדאי ליידע את המשתמש על כך שחלקים מסוימים בדף לא יפעלו כראוי.

הערה: האירוע controlling לא יופעל אם לא תתבצע קריאה ל-skipWaiting() דרך קובץ השירות (service worker).

קובץ השירות (service worker) סיים להפעיל activated לאחר שה-Service Worker המעודכן מסיים את ההפעלה, המשמעות היא שכל הלוגיקה שפעלתם ב-activate של ה-Service Worker הושלמה. אם צריך לדחות משהו עד שהלוגיקה תסתיים, זה הזמן להריץ אותה.

כאשר נמצאה גרסה לא צפויה של Service Worker

לפעמים המשתמשים משאירים את האתר פתוח בכרטיסיית רקע למשך זמן רב מאוד. יכול להיות שהם יפתחו כרטיסייה חדשה ויעברו לאתר בלי שתשימו לב שהאתר כבר פתוח בכרטיסייה ברקע. במקרים כאלה, יכולות להיות שתי גרסאות של האתר שפועלות בו-זמנית, וזה עלול לגרום לבעיות מעניינות מבחינתכם כמפתח/ת.

נבחן תרחיש שבו כרטיסייה א' מציגה את האתר v1, וכרטיסייה ב' מפעילה את v2. כשכרטיסייה ב' נטענת, היא נשלטת על ידי הגרסה של ה-service worker ששלחה את הגרסה 1, אבל הדף שהוחזר על ידי השרת (אם נעשה שימוש באסטרטגיית שמירה במטמון הראשון ברשת עבור בקשות הניווט) יכלול את כל נכסי v2.

עם זאת, בדרך כלל אין זו בעיה עבור כרטיסייה ב', מכיוון כשכתבתם את קוד v2, ידעתם איך קוד v1 פועל. עם זאת, זו עשויה להיות בעיה בכרטיסייה א',מכיוון שאין אפשרות לחזות שקוד v1 עשוי לחזות מה יגרמו לשינויים בקוד v2.

כדי לעזור בהתמודדות עם מצבים כאלה, workbox-window שולח גם אירועים של מחזור החיים כשהוא מזהה עדכון של קובץ שירות (service worker) 'חיצוני', כאשר המשמעות של אירוע חיצוני היא כל גרסה שהיא לא הגרסה הרשומה במכונה הנוכחית Workbox.

החל מגרסה Workbox v6 ואילך, האירועים האלה מקבילים לאירועים שתועדו למעלה, והוספת מאפיין isExternal: true לכל אובייקט אירוע. אם אפליקציית האינטרנט שלכם צריכה להטמיע לוגיקה ספציפית על מנת לטפל בקובץ שירות (service worker) 'חיצוני', תוכלו לבדוק את המאפיין הזה ברכיבי ה-handler של האירועים.

הימנעות מטעויות נפוצות

אחת התכונות המועילות ביותר ש-Workbox מספקת היא רישום ביומן של מפתחים. וזה נכון במיוחד לגבי workbox-window.

אנחנו יודעים שהפיתוח עם Service Worker עלול לפעמים להיות מבלבל, וכשדברים קורים בניגוד למה שציפיתם, קשה לדעת למה.

לדוגמה, כשמבצעים שינוי ב-Service Worker וטוענים מחדש את הדף, יכול להיות שהשינוי לא יופיע בדפדפן. הסיבה הסבירה ביותר לכך היא שה-Service Worker עדיין ממתין להפעלה.

אבל כשרושמים קובץ שירות (service worker) עם המחלקה Workbox, תקבלו הודעה על כל השינויים במצב מחזור החיים ב-Play Console, שיעזרו לכם בניפוי באגים הגורמים לכך שהמצבים לא תואמים לציפיות שלכם.

אזהרה לעובד ממתין במסוף

בנוסף, טעות נפוצה שמפתחים עושים כשהם משתמשים לראשונה ב-Service Worker היא לרשום Service Worker בהיקף הלא נכון.

כדי למנוע זאת, המחלקה Workbox תציג אזהרה אם הדף שרושם את קובץ השירות (service worker) לא נמצא בהיקף של אותו קובץ שירות. תוצג אזהרה גם במקרים שבהם קובץ השירות (service worker) פעיל אבל עדיין לא שולט בדף:

אזהרה לגבי מסוף עם חלון תיבת עבודה לעובד שאינו שולט

חלון לתקשורת של Service Worker

השימוש המתקדם ביותר ב-Service Worker כולל הרבה הודעות בין ה-service worker לבין החלון. המחלקה Workbox עוזרת בכך גם על ידי מתן שיטת messageSW(), שתpostMessage() את קובץ השירות (service worker) הרשום של המכונה ותמתין לתגובה.

אפשר לשלוח נתונים ל-Service Worker בכל פורמט, אבל הפורמט שמשותף לכל חבילות Workbox הוא אובייקט עם שלושה מאפיינים (השניים האחרונים הם אופציונליים):

מאפיין (property) חובה? סוג תיאור
type כן string

מחרוזת ייחודית המזהה את ההודעה.

לפי המוסכמה, כל סוגי האותיות הם אותיות רישיות, עם קווים תחתונים שמפרידים בין מילים. אם הסוג מייצג פעולה שצריך לבצע, הוא צריך להיות פקודה בזמן הנוכחי (למשל CACHE_URLS). אם הסוג מייצג מידע שדווח, הוא צריך להיות בזמן עבר (למשל, URLS_CACHED).

meta no string ב-Workbox זהו תמיד השם של חבילת Workbox ששולחת את ההודעה. כששולחים הודעה בעצמכם, אפשר להשמיט את המאפיין הזה או להגדיר אותו לבחירתכם.
payload no * הנתונים שנשלחים. בדרך כלל זה אובייקט, אבל זה לא חייב להיות.

הודעות שנשלחות בשיטה messageSW() משתמשות ב-MessageChannel כדי שהנמען יוכל להשיב להן. כדי לענות להודעות, אתם יכולים להתקשר למספר event.ports[0].postMessage(response) באמצעות event listener של ההודעה. השיטה messageSW() מחזירה להבטיח פתרון של כל response שאליו משיבים.

הנה דוגמה לשליחת הודעות מהחלון ל-Service Worker ולקבלת תגובה. בלוק הקוד הראשון הוא האזנה להודעות ב-service worker, והבלוק השני משתמש במחלקה Workbox כדי לשלוח את ההודעה ולהמתין לתגובה:

הקוד ב-sw.js:

const SW_VERSION = '1.0.0';

addEventListener('message', event => {
  if (event.data.type === 'GET_VERSION') {
    event.ports[0].postMessage(SW_VERSION);
  }
});

הקוד ב-main.js (פועל בחלון):

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, חשוב מאוד להיות מודעים לכך שייתכן שה-Service Worker לא מריץ את אותה גרסת אתר שבה פועל קוד הדף שלכם, והפתרון להתמודדות עם הבעיה הזו תלוי בשאלה אם הצגת הדפים קודם לכן ברשת או במטמון.

קודם רשת

כאשר הצגת רשת הדפים ראשונה, המשתמשים שלכם תמיד יקבלו את הגרסה העדכנית ביותר של ה-HTML מהשרת שלכם. עם זאת, בפעם הראשונה שמשתמש יבקר שוב באתר (לאחר פריסת עדכון), קוד ה-HTML שיקבל יהיה בגרסה העדכנית ביותר, אבל ה-Service Worker שפועל בדפדפן יקבל גרסה שהותקנה בעבר (כנראה בגרסאות ישנות רבות).

חשוב להבין את האפשרות הזו, כי אם קוד ה-JavaScript שנטען בגרסה הנוכחית של הדף שולח הודעה לגרסה ישנה יותר של Service Worker, יכול להיות שהגרסה הזו לא תדע איך להגיב (או שהיא עשויה להגיב בפורמט לא תואם).

לכן מומלץ תמיד לעדכן את קובץ השירות (service worker) ולבדוק אם יש גרסאות תואמות לפני שמבצעים עבודה קריטית.

לדוגמה, בקוד שלמעלה, אם גרסת ה-Service Worker שחזרה באמצעות הקריאה ל-messageSW() ישנה יותר מהגרסה הצפויה, מומלץ להמתין עד שיימצא עדכון (שצריך להתרחש כשקוראים ל-register()). בשלב הזה תוכלו להודיע למשתמש או לעדכן, או שתוכלו לדלג באופן ידני על שלב ההמתנה כדי להפעיל את ה-Service Worker החדש באופן מיידי.

קודם מטמון

בניגוד למקרים של הצגת דפים עם עדיפות לרשת, כשמציגים את הדפים במטמון, קודם כל יודעים שהדף תמיד יהיה באותה גרסה של ה-service worker (כי זה מה שפרסם אותו). לכן אפשר להשתמש ב-messageSW() באופן מיידי.

עם זאת, אם נמצאה גרסה מעודכנת של קובץ השירות (service worker) שלך ומופעלת בדף קריאה ל-register() (כלומר, דילגת על שלב ההמתנה בכוונה), ייתכן שלא בטוח לשלוח אליו הודעות.

אחת האסטרטגיות לניהול האפשרות הזו היא להשתמש בסכמה של ניהול גרסאות שמאפשרת להבחין בין עדכונים לבין עדכונים שלא עלולים לגרום לכשלים. במקרה של עדכון חשוב, אפשר לדעת שלא בטוח לשלוח הודעות ל-service worker. במקום זאת, כדאי להזהיר את המשתמש שהוא מפעיל גרסה ישנה של הדף, ולהציע לו לטעון מחדש כדי לקבל את העדכון.

דילוג על העוזר הדיגיטלי

מוסכמה מקובלת בשימוש בהעברת הודעות מחלון ל-Service Worker היא שליחת הודעת {type: 'SKIP_WAITING'} כדי להנחות את קובץ השירות (service worker) שהותקן לדלג על שלב ההמתנה ולהפעיל אותו.

החל מגרסה Workbox v6, אפשר להשתמש בשיטה messageSkipWaiting() כדי לשלוח הודעת {type: 'SKIP_WAITING'} ל-Service Worker שמשויך לרישום הנוכחי של ה-Service Worker. אם אין קובץ שירות (service worker) ממתין, לא יקרה דבר באופן שקט.

סוגים

Workbox

כיתה שמסייעת בטיפול ברישום של קובצי שירות, בעדכונים ובתגובה לאירועים במחזור החיים של Service Worker.

תכונות

  • Constructor

    void

    יצירת מכונה חדשה של Workbox עם כתובת URL של סקריפט ואפשרויות של Service Worker. כתובת ה-URL והאפשרויות של הסקריפט זהות לאפשרויות שמשתמשים בהן בזמן הקריאה ל-navigator.serviceWorker.register(scriptURL, options).

    הפונקציה constructor נראית כך:

    (scriptURL: string|TrustedScriptURL,registerOptions?: object)=> {...}

    • scriptURL

      מחרוזת|TrustedScriptURL

      הסקריפט של קובץ השירות (service worker) שמשויך למכונה הזו. יש תמיכה בשימוש ב-TrustedScriptURL.

    • registerOptions

      אובייקט אופציונלי

  • פעיל

    Promise<ServiceWorker>

  • שליטה

    Promise<ServiceWorker>

  • getSW

    void

    הפרמטר מקבל את האישור עם הפניה ל-Service Worker שתואם לכתובת ה-URL של הסקריפט של המכונה הזו, ברגע שהיא זמינה.

    אם בזמן הרישום כבר יש worker פעיל או בהמתנה עם כתובת URL תואמת של סקריפט, הוא יהיה בשימוש (וכאשר שניהם יהיו תואמים, הוא יקבל עדיפות על פני ה-Service Worker, כי הוא היה רשום יותר לאחרונה). אם לא נמצא קובץ שירות (service worker) תואם או פעיל בזמן הרישום, ההבטחה לא תטופל עד שיימצא עדכון ותתחיל להתקין אותו, ובשלב הזה ייעשה שימוש ב-Service Worker שמתקין.

    הפונקציה getSW נראית כך:

    ()=> {...}

    • החזרות

      Promise<ServiceWorker>

  • messageSW

    void

    שולח את אובייקט הנתונים שהועבר ל-Service Worker שרשום במכונה הזו (באמצעות workbox-window.Workbox#getSW) ומקודד עם תגובה (אם יש).

    ניתן לך להגדיר תגובה ב-handler של הודעות ב-Service Worker על ידי קריאה ל-event.ports[0].postMessage(...), וכך תפתור את ההבטחה שהוחזרה על ידי messageSW(). אם לא תתקבל תשובה, ההבטחה לא תטופל אף פעם.

    הפונקציה messageSW נראית כך:

    (data: object)=> {...}

    • נתונים

      אובייקט

      אובייקט לשליחה ל-Service Worker

    • החזרות

      מבטיח<any>

  • messageSkipWaiting

    void

    נשלחת הודעת {type: 'SKIP_WAITING'} ל-Service Worker שנמצא כרגע במצב waiting שמשויך לרישום הנוכחי.

    אם לא קיים רישום נוכחי או שאין קובץ שירות (service worker) הוא waiting, קריאה לפעולה הזו לא תשפיע.

    הפונקציה messageSkipWaiting נראית כך:

    ()=> {...}

  • register

    void

    רושם את קובץ השירות (service worker) לכתובת ה-URL של הסקריפט של המכונה הזו ולאפשרויות של ה-Service Worker. כברירת מחדל, השיטה הזו תשהה את הרישום עד שהחלון ייטען.

    הפונקציה register נראית כך:

    (options?: object)=> {...}

    • אפשרויות

      אובייקט אופציונלי

      • מיידי

        בוליאני אופציונלי

    • החזרות

      Promise<ServiceWorkerRegistration>

  • update

    void

    חיפוש עדכונים של Service Worker הרשום.

    הפונקציה update נראית כך:

    ()=> {...}

    • החזרות

      Promise<void>

WorkboxEventMap

תכונות

WorkboxLifecycleEvent

תכונות

  • isExternal

    בוליאני אופציונלי

  • isUpdate

    בוליאני אופציונלי

  • originalEvent

    אירוע אופציונלי

  • sw

    ServiceWorker אופציונלי

  • יעד

    WorkboxEventTarget אופציונלי

  • סוג

    typeOperator

WorkboxLifecycleEventMap

תכונות

WorkboxLifecycleWaitingEvent

תכונות

  • isExternal

    בוליאני אופציונלי

  • isUpdate

    בוליאני אופציונלי

  • originalEvent

    אירוע אופציונלי

  • sw

    ServiceWorker אופציונלי

  • יעד

    WorkboxEventTarget אופציונלי

  • סוג

    typeOperator

  • wasWaitingBeforeRegister

    בוליאני אופציונלי

WorkboxMessageEvent

תכונות

  • נתונים

    הכול

  • isExternal

    בוליאני אופציונלי

  • originalEvent

    אירוע

  • ports

    typeOperator

  • sw

    ServiceWorker אופציונלי

  • יעד

    WorkboxEventTarget אופציונלי

  • סוג

שיטות

messageSW()

workbox-window.messageSW(
  sw: ServiceWorker,
  data: object,
)

שליחת אובייקט נתונים ל-Service Worker דרך postMessage והחלפתו בתגובה (אם יש).

ניתן לך להגדיר תגובה ב-handler של הודעות ב-Service Worker על ידי קריאה ל-event.ports[0].postMessage(...), וכך תפתור את ההבטחה שהוחזרה על ידי messageSW(). אם לא תוגדר תשובה, ההבטחה לא תטופל.

פרמטרים

  • sw

    ServiceWorker

    קובץ השירות (service worker) שאליו יש לשלוח את ההודעה.

  • נתונים

    אובייקט

    אובייקט לשליחה ל-Service Worker.

החזרות

  • מבטיח<any>