כששולחים נתונים לשרת אינטרנט, לפעמים הבקשות נכשלות. זה יכול לקרות בגלל שהמשתמש איבד את הקישוריות, או בגלל שהשרת מושבת. לא תמיד כדאי לנסות לשלוח את הבקשות שוב מאוחר יותר.
ה-BackgroundSync API החדש הוא פתרון אידיאלי לבעיה הזו. כש-Service Worker מזהה שבקשת רשת נכשלה, הוא יכול להירשם לקבלת אירוע sync
, שמוסר כשהדפדפן מזהה שהקישוריות ממשיכה לחזור.
שימו לב שאפשר להעביר את אירוע הסנכרון גם אם המשתמש יצא מהאפליקציה, ולכן הוא יעיל הרבה יותר מהשיטה המסורתית של ניסיון חוזר של בקשות שנכשלו.
השירות 'סנכרון ברקע של Workbox' נועד להקל על השימוש ב-BackgroundSync API ולשלב את השימוש בו עם מודולים אחרים של Workbox. היא גם מיישמת אסטרטגיית גיבוי לדפדפנים שעדיין לא הטמיעו את BackgroundSync.
דפדפנים שתומכים ב-BackgroundSync API ישיבו בשמכם באופן אוטומטי בקשות שנכשלו במרווח הזמן שמנוהל על ידי הדפדפן, סביר להניח שישתמשו בהשהיה מעריכית לפני ניסיון חוזר (exponential backoff) בין ניסיונות ההפעלה החוזרת. בדפדפנים שלא תומכים במקור ב-BackgroundSync API, הסנכרון ברקע ב-Workbox Background Sync ינסה באופן אוטומטי להפעיל מחדש בכל פעם שה-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
מתחבר אל קריאה חוזרת (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.
שימוש מתקדם
סנכרון ברקע של תיבת העבודה גם מספק מחלקה Queue
, שאליה אפשר ליצור ולהוסיף בקשות שנכשלו. הבקשות שנכשלו מאוחסנות ב-IndexedDB ומתבצעות שוב כשהדפדפן מזהה שהקישוריות משוחזרת (כלומר, כשהוא מקבל את אירוע הסנכרון).
יצירת תור
כדי ליצור תור לסנכרון ברקע של תיבת עבודה, עליך ליצור אותו עם שם תור (שחייב להיות ייחודי למקור שלך):
import {Queue} from 'workbox-background-sync';
const queue = new Queue('myQueueName');
שם התור משמש כחלק משם התג שמקבל את הפרמטר register()
מהתג הגלובלי SyncManager
. הוא משמש גם כשם Object Store למסד הנתונים 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 היא לא אינטואיטיבית במידה מסוימת וקשה מכמה סיבות.
הדרך הטובה ביותר לבדוק את ההטמעה היא:
- טוענים דף ורושמים את קובץ השירות (service worker).
- מכבים את הרשת של המחשב או מכבים את שרת האינטרנט.
- אין להשתמש בכלי הפיתוח של Chrome במצב אופליין. תיבת הסימון של מצב אופליין בכלי הפיתוח משפיעה רק על בקשות מהדף. בקשות של Service Worker ימשיכו להישלח.
- ביצוע בקשות רשת שצריך להוסיף לתור עם Workbox Background Sync.
- אפשר לבדוק את הבקשות בתור
ב-
Chrome DevTools > Application > IndexedDB > workbox-background-sync > requests
- אפשר לבדוק את הבקשות בתור
ב-
- עכשיו צריך להפעיל את הרשת או את שרת האינטרנט.
כדי לאלץ אירוע
sync
מוקדם יותר, עוברים אלChrome DevTools > Application > Service Workers
, מזינים את שם התג שלworkbox-background-sync:<your queue name>
כאשר<your queue name>
צריך להיות שם התור שהגדרתם, ולוחצים על הלחצן Sync.אתם אמורים לראות שמתבצעות בקשות רשת עבור הבקשות שנכשלו, והנתונים ב-IndexedDB אמורים להיות ריקים כי הבקשות הופעלו מחדש בהצלחה.
סוגים
BackgroundSyncPlugin
מחלקה שמטמיעה את הקריאה החוזרת של מחזור החיים של fetchDidFail
. כך קל יותר להוסיף בקשות שנכשלו לתור לסנכרון ברקע.
תכונות
-
Constructor
void
הפונקציה
constructor
נראית כך:(name: string, options?: QueueOptions) => {...}
-
name
מחרוזת
במאמרי העזרה בנושא
workbox-background-sync.Queue
תוכלו לקרוא פרטים נוספים על הפרמטרים. -
אפשרויות
QueueOptions אופציונלי
-
החזרות
-
Queue
מחלקה לניהול אחסון הבקשות שנכשלו ב-IndexedDB, וניסיון חוזר מאוחר יותר. ניתן לתעד את כל החלקים בתהליך האחסון וההפעלה מחדש באמצעות קריאה חוזרת (callback).
תכונות
-
Constructor
void
יצירת מופע של 'הבאים בתור' עם האפשרויות הנתונות
הפונקציה
constructor
נראית כך:(name: string, options?: QueueOptions) => {...}
-
name
מחרוזת
השם הייחודי של התור הזה. השם הזה חייב להיות ייחודי כי הוא משמש לרישום אירועי סנכרון ובקשות לאחסון ב-IndexedDB הספציפי למכונה הזו. תוצג הודעת שגיאה אם יזוהה שם כפול.
-
אפשרויות
QueueOptions אופציונלי
-
החזרות
-
-
name
מחרוזת
-
getAll
void
הפונקציה מחזירה את כל הרשומות שתוקפן לא פג (לכל
maxRetentionTime
). כל הרשומות שהתוקף שלהן פג יוסרו מהתור.הפונקציה
getAll
נראית כך:() => {...}
-
החזרות
Promise<QueueEntry[]>
-
-
popRequest
void
מסירה ומחזירה את הבקשה האחרונה בתור (עם חותמת הזמן והמטא-נתונים שלה). האובייקט שמוחזר מופיע בתבנית הבאה:
{request, timestamp, metadata}
.הפונקציה
popRequest
נראית כך:() => {...}
-
החזרות
Promise<QueueEntry>
-
-
pushRequest
void
שמירת הבקשה שהועברה ב-IndexedDB (עם חותמת הזמן והמטא-נתונים שלה) בסוף התור.
הפונקציה
pushRequest
נראית כך:(entry: QueueEntry) => {...}
-
רשומה
QueueEntry
-
החזרות
Promise<void>
-
-
registerSync
void
רישום אירוע סנכרון עם תג ייחודי למופע הזה.
הפונקציה
registerSync
נראית כך:() => {...}
-
החזרות
Promise<void>
-
-
replayRequests
void
עובר על כל בקשה בתור ומנסה לאחזר אותה מחדש. אם בקשה מסוימת נכשלת בשליפה מחדש, היא מוחזרת לאותו מיקום בתור (בתור נתון מתועד ניסיון חוזר לאירוע הסנכרון הבא).
הפונקציה
replayRequests
נראית כך:() => {...}
-
החזרות
Promise<void>
-
-
shiftRequest
void
מסירה ומחזירה את הבקשה הראשונה בתור (עם חותמת הזמן והמטא-נתונים שלה). האובייקט שמוחזר מופיע בתבנית הבאה:
{request, timestamp, metadata}
.הפונקציה
shiftRequest
נראית כך:() => {...}
-
החזרות
Promise<QueueEntry>
-
-
גודל
void
מחזירה את מספר הרשומות שנמצאות בתור. חשוב לשים לב שהספירה הזו כוללת גם רשומות שהתוקף שלהן פג (לכל
maxRetentionTime
).הפונקציה
size
נראית כך:() => {...}
-
החזרות
הבטחה<number>
-
-
unshiftRequest
void
שמירת הבקשה שהועברה ב-IndexedDB (עם חותמת הזמן והמטא-נתונים שלה) בתחילת התור.
הפונקציה
unshiftRequest
נראית כך:(entry: QueueEntry) => {...}
-
רשומה
QueueEntry
-
החזרות
Promise<void>
-
QueueOptions
תכונות
-
forceSyncFallback
בוליאני אופציונלי
-
maxRetentionTime
מספר אופציונלי
-
onSync
OnSyncCallback אופציונלי
QueueStore
מחלקה לניהול בקשות אחסון מתור ב-IndexedDB, שמתווספת לאינדקס לפי שם התור, לגישה קלה יותר.
רוב המפתחים לא יצטרכו לגשת לכיתה הזו ישירות, אלא רק בתרחישים מתקדמים.
תכונות
-
Constructor
void
משייכת את המכונה הזו למופע של 'הבאים בתור', כך שאפשר לזהות את הרשומות שנוספו לפי שם התור.
הפונקציה
constructor
נראית כך:(queueName: string) => {...}
-
queueName
מחרוזת
-
החזרות
-
-
deleteEntry
void
מחיקת הרשומה של המזהה הנתון.
אזהרה: השיטה הזו לא מבטיחה שהרשומה שנמחקה שייכת לתור הזה (כלומר, תואמת לערך
queueName
), אבל המגבלה הזו קבילה כי המחלקה לא נחשפת באופן ציבורי. בדיקה נוספת תאט את מהירות השיטה.הפונקציה
deleteEntry
נראית כך:(id: number) => {...}
-
id
מספר
-
החזרות
Promise<void>
-
-
getAll
void
מחזירה את כל הרשומות בחנות שתואמות ל-
queueName
.הפונקציה
getAll
נראית כך:() => {...}
-
החזרות
Promise<QueueStoreEntry[]>
-
-
popEntry
void
מסירה ומחזירה את הרשומה האחרונה בתור שתואמת ל-
queueName
.הפונקציה
popEntry
נראית כך:() => {...}
-
החזרות
Promise<QueueStoreEntry>
-
-
pushEntry
void
הוספת ערך אחרון בתור.
הפונקציה
pushEntry
נראית כך:(entry: UnidentifiedQueueStoreEntry) => {...}
-
רשומה
UnidentifiedQueueStoreEntry
-
החזרות
Promise<void>
-
-
shiftEntry
void
מסירה ומחזירה את הרשומה הראשונה בתור שתואמת ל-
queueName
.הפונקציה
shiftEntry
נראית כך:() => {...}
-
החזרות
Promise<QueueStoreEntry>
-
-
גודל
void
מחזירה את מספר הרשומות בחנות שתואמות ל-
queueName
.הפונקציה
size
נראית כך:() => {...}
-
החזרות
הבטחה<number>
-
-
unshiftEntry
void
צריך להוסיף קודם רשומה בתור.
הפונקציה
unshiftEntry
נראית כך:(entry: UnidentifiedQueueStoreEntry) => {...}
-
רשומה
UnidentifiedQueueStoreEntry
-
החזרות
Promise<void>
-
StorableRequest
מחלקה שמקל
רוב המפתחים לא יצטרכו לגשת לכיתה הזו ישירות, אלא רק בתרחישים מתקדמים.
תכונות
-
Constructor
void
מקבל אובייקט של נתוני בקשה שאפשר להשתמש בו כדי ליצור
Request
, אבל אפשר לשמור אותו גם ב-IndexedDB.הפונקציה
constructor
נראית כך:(requestData: RequestData) => {...}
-
requestData
RequestData
אובייקט של נתוני בקשה שכולל את
url
וגם את כל המאפיינים הרלוונטיים של [requestInit]https://fetch.spec.whatwg.org/#requestinit
.
-
החזרות
-
-
שכפול
void
יוצרת ומחזירה שכפול עמוק של המכונה.
הפונקציה
clone
נראית כך:() => {...}
-
החזרות
-
-
toObject
void
מחזירה שכפול עמוק של האובייקט
_requestData
של האובייקט.הפונקציה
toObject
נראית כך:() => {...}
-
החזרות
RequestData
-
-
toRequest
void
ממיר את המופע הזה לבקשה.
הפונקציה
toRequest
נראית כך:() => {...}
-
החזרות
בקשה
-
-
fromRequest
void
ממירה אובייקט של Request לאובייקט פשוט שאפשר לשכפל או ליצור מחרוזת JSON.
הפונקציה
fromRequest
נראית כך:(request: Request) => {...}
-
בקשה
בקשה
-
החזרות
Promise<StorableRequest>
-