תיבת עבודה-רקע-סנכרון

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

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

'סנכרון ברקע של תיבת העבודה' נועד להקל על השימוש BackgroundSync API ושילוב השימוש שלו עם מודולים אחרים של Workbox. הוא מיישם גם אסטרטגיה חלופית לדפדפנים שעדיין לא מטמיעים BackgroundSync.

דפדפנים שתומכים ב-BackgroundSync API מפעילים מחדש באופן אוטומטי את כישלון בקשות בשמך מרווח הזמן שמנוהל על ידי הדפדפן, סביר להניח שנעשה שימוש בהשהיה מעריכית לפני ניסיון חוזר (exponential backoff) בין ניסיונות הפעלה חוזרת. בדפדפנים אינם תומכים במקור ב-BackgroundSync API, 'סנכרון ברקע של Workbox' ינסה להפעיל מחדש באופן אוטומטי בכל פעם שה-Service Worker מופעל.

שימוש בסיסי

הדרך הקלה ביותר להשתמש ב'סנכרון ברקע' היא להשתמש ב-Plugin הוספה אוטומטית של בקשות שנכשלו לתור ולנסות שוב כאשר sync בעתיד האירועים מופעלים.

import {BackgroundSyncPlugin} from 'workbox-background-sync';
import {registerRoute} from 'workbox-routing';
import {NetworkOnly} from 'workbox-strategies';

const bgSyncPlugin = new BackgroundSyncPlugin('myQueueName', {
  maxRetentionTime: 24 * 60, // Retry for max of 24 Hours (specified in minutes)
});

registerRoute(
  /\/api\/.*\/*.json/,
  new NetworkOnly({
    plugins: [bgSyncPlugin],
  }),
  'POST'
);

BackgroundSyncPlugin קטעי הוק (hooks) אל קריאה חוזרת (callback) של הפלאגין fetchDidFail, וגם המערכת של fetchDidFail מופעלת רק אם אירעה חריגה, ככל הנראה הסיבה כשל רשת. כלומר, לא יתבצע ניסיון חוזר לבקשות אם תשובה שהתקבלה עם סטטוס שגיאה 4xx או 5xx. אם ברצונך לנסות שוב את כל הבקשות שהתוצאה שלהן היא, למשל, הסטטוס 5xx, אפשר לעשות את זה על ידי הוספת פלאגין fetchDidSucceed של אסטרטגיית הפרסום שלכם:

const statusPlugin = {
  fetchDidSucceed: ({response}) => {
    if (response.status >= 500) {
      // Throwing anything here will trigger fetchDidFail.
      throw new Error('Server error.');
    }
    // If it's not 5xx, use the response as-is.
    return response;
  },
};

// Add statusPlugin to the plugins array in your strategy.

שימוש מתקדם

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

יצירת תור

כדי ליצור תור לסנכרון ברקע של Workbox, צריך ליצור אותו עם שם תור (שחייב להיות ייחודי origin):

import {Queue} from 'workbox-background-sync';

const queue = new Queue('myQueueName');

שם התור משמש כחלק משם התג שמתקבל register() ברחבי העולם SyncManager זו משמש גם שם מאגר האובייקטים של מסד הנתונים IndexedDB.

הוספת בקשה לתור

אחרי שיוצרים מופע מסוג 'הבאים בתור', אפשר להוסיף לו בקשות שנכשלו. כדי להוסיף בקשה שנכשלה, יש להפעיל את השיטה .pushRequest(). לדוגמה, הקוד הבא מאתר בקשות שנכשלו ומוסיף אותן לתור:

import {Queue} from 'workbox-background-sync';

const queue = new Queue('myQueueName');

self.addEventListener('fetch', event => {
  // Add in your own criteria here to return early if this
  // isn't a request that should use background sync.
  if (event.request.method !== 'POST') {
    return;
  }

  const bgSyncLogic = async () => {
    try {
      const response = await fetch(event.request.clone());
      return response;
    } catch (error) {
      await queue.pushRequest({request: event.request});
      return error;
    }
  };

  event.respondWith(bgSyncLogic());
});

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

בדיקת סנכרון ברקע של תיבת העבודה

לצערי, הבדיקה של BackgroundSync די לא אינטואיטיבית וקשה מכמה סיבות.

הגישה הטובה ביותר לבדיקת ההטמעה היא לבצע את הפעולות הבאות:

  1. טוענים דף ורושמים את Service Worker.
  2. משביתים את הרשת של המחשב או את שרת האינטרנט.
    • אין להשתמש בכלי הפיתוח ל-Chrome ללא חיבור לאינטרנט. תיבת הסימון למצב אופליין ב- כלי הפיתוח משפיעים רק על בקשות מהדף. בקשות של קובץ שירות (service worker) ימשיכו לפעול.
  3. יצירת בקשות רשת שצריך להוסיף לתור עם 'סנכרון ברקע של Workbox'.
    • אפשר לבדוק שהבקשות הגיעו לתור Chrome DevTools > Application > IndexedDB > workbox-background-sync > requests
  4. עכשיו מפעילים את הרשת או את שרת האינטרנט.
  5. אילוץ אירוע sync מוקדם באמצעות מעבר אל Chrome DevTools > Application > Service Workers, הזנת שם התג של workbox-background-sync:<your queue name> במקום <your queue name> צריך להיות שם התור שהגדרת, ולאחר מכן לחיצה על 'סנכרון' לחצן.

    דוגמה ללחצן &#39;סנכרון&#39; בכלי הפיתוח ל-Chrome

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

סוגים

BackgroundSyncPlugin

מחלקה שמממשת את הקריאה החוזרת (callback) של מחזור החיים fetchDidFail. ככה קל יותר להוסיף בקשות שנכשלו לתור לסנכרון ברקע.

מאפיינים

Queue

מחלקה לניהול אחסון בקשות שנכשלו ב-IndexedDB וניסיון חוזר שלהן מאוחר יותר. ניתן לצפות בכל החלקים של תהליך האחסון וההפעלה מחדש דרך קריאה חוזרת (callback).

מאפיינים

  • constructor

    ריק

    יצירת מופע של Queue עם האפשרויות הנתונות

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

    (name: string, options?: QueueOptions) => {...}

    • שם

      מחרוזת

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

    • אפשרויות

      QueueOptions אופציונלי

  • שם

    מחרוזת

  • getAll

    ריק

    הפונקציה מחזירה את כל הרשומות שהתוקף שלהן לא פג (לכל maxRetentionTime). כל הערכים שהתוקף שלהם פג יוסרו מ'הבאים בתור'.

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

    () => {...}

    • החזרות

      Promise&lt;QueueEntry[]&gt;

  • popRequest

    ריק

    הסרה והחזרה של הבקשה האחרונה בתור (יחד עם חותמת זמן וכל מטא-נתונים). האובייקט המוחזר מופיע בפורמט: {request, timestamp, metadata}

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

    () => {...}

    • החזרות

      Promise&lt;QueueEntry&gt;

  • pushRequest

    ריק

    שמירת הבקשה שהועברה ב-IndexedDB (עם חותמת הזמן וכל בסוף התור.

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

    (entry: QueueEntry) => {...}

    • ערך

      QueueEntry

    • החזרות

      הבטחה<Empty>

  • registerSync

    ריק

    רושם אירוע סנכרון עם תג ייחודי למופע הזה.

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

    () => {...}

    • החזרות

      הבטחה<Empty>

  • replayRequests

    ריק

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

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

    () => {...}

    • החזרות

      הבטחה<Empty>

  • shiftRequest

    ריק

    הסרה והחזרה של הבקשה הראשונה בתור (יחד עם חותמת זמן וכל מטא-נתונים). האובייקט המוחזר מופיע בפורמט: {request, timestamp, metadata}

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

    () => {...}

    • החזרות

      Promise&lt;QueueEntry&gt;

  • size

    ריק

    מחזירה את מספר הערכים שנמצאים בתור. חשוב לשים לב שגם רשומות שהתוקף שלהן פג (לכל maxRetentionTime) נכללות בספירה הזו.

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

    () => {...}

    • החזרות

      Promise&lt;number&gt;

  • unshiftRequest

    ריק

    שמירת הבקשה שהועברה ב-IndexedDB (עם חותמת הזמן וכל מטא-נתונים) בתחילת התור.

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

    (entry: QueueEntry) => {...}

    • ערך

      QueueEntry

    • החזרות

      הבטחה<Empty>

QueueOptions

מאפיינים

  • forceSyncFallback

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

  • maxRetentionTime

    מספר אופציונלי

  • onSync

    OnSyncCallback (אופציונלי) אופציונלי

QueueStore

מחלקה לניהול בקשות אחסון מתור ב-IndexedDB, נוספו לאינדקס לפי שם התור כדי לגשת אליהן בקלות.

רוב המפתחים לא יצטרכו לגשת לכיתה הזו ישירות. הוא חשוף בתרחישים מתקדמים לדוגמה.

מאפיינים

  • constructor

    ריק

    משייך את המופע הזה למופע של 'תור', כך שערכים שנוספו יכולים להיות מזוהה לפי שם התור.

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

    (queueName: string) => {...}

    • queueName

      מחרוזת

  • deleteEntry

    ריק

    מוחק את הרשומה של המזהה הנתון.

    אזהרה: השיטה הזו לא מבטיחה שהרשומה שנמחקה שייכת תור (כלומר תואם ל-queueName). אבל ההגבלה הזו מקובלת. כי הסיווג הזה לא גלוי לכולם. בדיקה נוספת תאפשר השיטה הזו איטית יותר ממה שהיא צריכה.

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

    (id: number) => {...}

    • id [מזהה]

      number

    • החזרות

      הבטחה<Empty>

  • getAll

    ריק

    הפונקציה מחזירה את כל הרשומות בחנות שתואמות לערך queueName.

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

    () => {...}

    • החזרות

      Promise&lt;QueueStoreEntry[]&gt;

  • popEntry

    ריק

    הפונקציה מסירה ומחזירה את הערך האחרון בתור שתואם ל-queueName.

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

    () => {...}

    • החזרות

      Promise&lt;QueueStoreEntry&gt;

  • pushEntry

    ריק

    צירוף רשומה אחרונה בתור.

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

    (entry: UnidentifiedQueueStoreEntry) => {...}

    • ערך

      UnidentifiedQueueStoreEntry

    • החזרות

      הבטחה<Empty>

  • shiftEntry

    ריק

    הפונקציה מסירה ומחזירה את הרשומה הראשונה בתור שתואמת ל-queueName.

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

    () => {...}

    • החזרות

      Promise&lt;QueueStoreEntry&gt;

  • size

    ריק

    הפונקציה מחזירה את מספר הרשומות בחנות שתואמות ל-queueName.

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

    () => {...}

    • החזרות

      Promise&lt;number&gt;

  • unshiftEntry

    ריק

    צריך להוסיף רשומה ראשונה בתור.

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

    (entry: UnidentifiedQueueStoreEntry) => {...}

    • ערך

      UnidentifiedQueueStoreEntry

    • החזרות

      הבטחה<Empty>

StorableRequest

כיתה שמקלה על הסידור והסידור של בקשות לפי סריאליזציה, כך שהן אפשר לאחסן ב-IndexedDB.

רוב המפתחים לא יצטרכו לגשת לכיתה הזו ישירות. הוא חשוף בתרחישים מתקדמים לדוגמה.

מאפיינים

  • constructor

    ריק

    מקבל אובייקט של נתוני בקשה שיכול לשמש לבניית אובייקט Request אבל ניתן לאחסן אותו גם ב-IndexedDB.

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

    (requestData: RequestData) => {...}

    • requestData

      RequestData

      אובייקט של נתוני בקשה שכולל את המאפיין url בתוספת כל מאפיין רלוונטי של [requestInit]https://fetch.spec.whatwg.org/#requestinit.

  • שכפל

    ריק

    יצירה והחזרה של שכפול עמוק של המכונה.

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

    () => {...}

  • toObject

    ריק

    מחזירה שכפול עמוק של המופעים _requestData.

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

    () => {...}

    • החזרות

      RequestData

  • toRequest

    ריק

    הפונקציה ממירה את המופע הזה ל-Request.

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

    () => {...}

    • החזרות

      בקשה

  • fromRequest

    ריק

    ממירה אובייקט Request [בקשה] לאובייקט פשוט שיכול להיות מובנה שכפול או מחרוזת JSON.

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

    (request: Request) => {...}

    • בקשה

      בקשה