בשנת 2015 השקנו את Background Sync, שמאפשר ל-service worker לדחות את העבודה עד שהמשתמש מתחבר לאינטרנט. המשמעות היא שהמשתמש יכול להקליד הודעה, ללחוץ על שליחה ולצאת מהאתר בידיעה שההודעה תישלח עכשיו או כשהוא יתחבר לאינטרנט.
זו תכונה שימושית, אבל כדי להשתמש בה צריך ש-Service Worker יפעל למשך זמן האחזור. זה לא בעייתי כשמדובר במשימות קצרות כמו שליחת הודעה, אבל אם המשימה אורכת יותר מדי זמן, הדפדפן יסגור את ה-Service Worker, אחרת יש סיכון לפרטיות ולסוללה של המשתמש.
אז מה קורה אם אתם צריכים להוריד משהו שיכול לקחת הרבה זמן, כמו סרט, פודקאסטים או שלבים במשחק? לשם כך נועד אחזור ברקע.
התכונה Background Fetch זמינה כברירת מחדל החל מ-Chrome 74.
הנה הדגמה קצרה של שתי דקות שבה מוצג המצב הרגיל, לעומת שימוש באחזור ברקע:
איך זה עובד
כך מתבצע אחזור ברקע:
- מנחים את הדפדפן לבצע קבוצה של אחזורים ברקע.
- הדפדפן מאחזר את הפריטים האלה ומציג את ההתקדמות למשתמש.
- אחרי שהפעולה הושלמה או נכשלה, הדפדפן פותח את ה-service worker ושולח אירוע כדי לעדכן אתכם לגבי מה שקרה. כאן מחליטים מה לעשות עם התשובות, אם בכלל.
גם אם המשתמש סוגר את הדפים באתר אחרי שלב 1, ההורדה תימשך. הפעולה הזו גלויה מאוד וקל לבטל אותה, ולכן אין חשש לפרטיות כמו במקרה של משימת סנכרון ברקע שנמשכת זמן רב מדי. מאחר ש-service worker לא פועל כל הזמן, אין חשש שהוא ינצל לרעה את המערכת, למשל יכרה ביטקוין ברקע.
בפלטפורמות מסוימות (כמו Android), יכול להיות שהדפדפן ייסגר אחרי שלב 1, כי הדפדפן יכול להעביר את האחריות על האחזור למערכת ההפעלה.
אם המשתמש מתחיל את ההורדה כשהוא אופליין, או עובר למצב אופליין במהלך ההורדה, אחזור הנתונים ברקע יושהה ויחודש מאוחר יותר.
API
זיהוי תכונות
כמו בכל תכונה חדשה, צריך לבדוק אם הדפדפן תומך בה. כדי להשתמש באחזור ברקע, פשוט מוסיפים את הקוד הבא:
if ('BackgroundFetchManager' in self) {
// This browser supports Background Fetch!
}
התחלת אחזור ברקע
ה-API הראשי תלוי ברישום של קובץ שירות (service worker), לכן חשוב לוודא שרשמתם קובץ שירות קודם. לאחר מכן:
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,
});
});
הפונקציה backgroundFetch.fetch
מקבלת שלושה ארגומנטים:
פרמטרים | |
---|---|
id |
string מזהה באופן ייחודי את האחזור הזה ברקע. |
requests |
Array<Request|string>
הפריטים לאחזור. מחרוזות יטופלו ככתובות URL ויהפכו ל- Request באמצעות new Request(theString) .
אפשר לאחזר נתונים ממקורות אחרים כל עוד המשאבים מאפשרים זאת באמצעות CORS. הערה: דפדפן Chrome לא תומך כרגע בבקשות שדורשות בדיקת קדם-הפעלה של CORS. |
options |
אובייקט שעשוי לכלול את המאפיינים הבאים: |
options.title |
string כותרת שתוצג בדפדפן לצד ההתקדמות. |
options.icons |
Array<IconDefinition> מערך של אובייקטים עם מאפיינים של `src`, `size` ו-`type`. |
options.downloadTotal |
number הגודל הכולל של גופי התגובה (אחרי ביטול הדחיסה ב-gzip). הוספת המידע הזה היא אופציונלית, אבל מומלצת מאוד. הוא משמש כדי להציג למשתמש את גודל ההורדה ולספק מידע על ההתקדמות. אם לא תספקו את הערך הזה, הדפדפן יציג למשתמש שהגודל לא ידוע, וכתוצאה מכך יש סיכוי גבוה יותר שהמשתמש יבטל את ההורדה. אם ההורדות של האחזור ברקע יעברו את המספר שצוין כאן, הפעולה תבוטל. אין בעיה אם גודל ההורדה קטן מ- |
backgroundFetch.fetch
מחזירה הבטחה שמושלמת עם BackgroundFetchRegistration
. אפרט על כך בהמשך. ההבטחה נדחית אם המשתמש ביטל את ההסכמה להורדות, או אם אחד מהפרמטרים שסופקו לא תקין.
כששולחים הרבה בקשות לאחזור נתונים ברקע, אפשר לשלב בין דברים שלמשתמש נראים כדבר אחד. לדוגמה, סרט יכול להיות מחולק לאלפי משאבים (בדרך כלל בפורמט MPEG-DASH), ויכולים להיות לו משאבים נוספים כמו תמונות. רמה במשחק יכולה להתפרס על פני משאבים רבים של JavaScript, תמונות ואודיו. אבל מבחינת המשתמש, זה פשוט 'הסרט' או 'השלב'.
אחזור ברקע של נתונים קיימים
כך אפשר לקבל אחזור קיים של נתונים ברקע:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});
…על ידי העברת המזהה של אחזור הנתונים ברקע שרוצים. הפונקציה get
מחזירה undefined
אם אין אחזור פעיל ברקע עם המזהה הזה.
אחזור נתונים ברקע נחשב 'פעיל' מהרגע שהוא נרשם, עד שהוא מצליח, נכשל או מבוטל.
אפשר לקבל רשימה של כל האחזורים הפעילים ברקע באמצעות getIds
:
navigator.serviceWorker.ready.then(async (swReg) => {
const ids = await swReg.backgroundFetch.getIds();
});
הרשמות לאחזור ברקע
ל-BackgroundFetchRegistration
(bgFetch
בדוגמאות שלמעלה) יש את המאפיינים הבאים:
מאפיינים | |
---|---|
id |
string המזהה של האחזור ברקע. |
uploadTotal |
number מספר הבייטים שיישלחו לשרת. |
uploaded |
number מספר הבייטים שנשלחו בהצלחה. |
downloadTotal |
number הערך שסופק כשנרשם אחזור הנתונים ברקע, או אפס. |
downloaded |
number מספר הבייטים שהתקבלו בהצלחה. הערך הזה עשוי לרדת. לדוגמה, אם החיבור נכשל ואי אפשר להמשיך את ההורדה, הדפדפן יפעיל מחדש את האחזור של המשאב הזה מההתחלה. |
result |
אחד מהבאים:
|
failureReason |
אחד מהבאים:
|
recordsAvailable |
boolean האם יש גישה לבקשות ולתשובות הבסיסיות? אם הערך הוא False, אי אפשר להשתמש ב- |
Methods | |
abort() |
מחזירה Promise<boolean> ביטול האחזור ברקע. ההבטחה שמוחזרת מסתיימת עם הערך true אם הבאת הנתונים בוטלה בהצלחה. |
matchAll(request, opts) |
מחזירה Promise<Array<BackgroundFetchRecord>> Get the requests and responses. הארגומנטים כאן זהים לארגומנטים של ה-API של המטמון. קריאה ללא ארגומנטים מחזירה הבטחה לכל הרשומות. המידע על הסיבות האפשריות מפורט כאן. |
match(request, opts) |
מחזירה Promise<BackgroundFetchRecord> כמו למעלה, אבל מחזירה את ההתאמה הראשונה. |
אירועים | |
progress |
התגובה מופעלת כשמתרחש שינוי באחד מהערכים הבאים: uploaded , downloaded , result או failureReason . |
מעקב אחר ההתקדמות
אפשר לעשות זאת באמצעות האירוע progress
. חשוב לזכור שהערך של downloadTotal
הוא הערך שסיפקתם, או 0
אם לא סיפקתם ערך.
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}%`);
});
קבלת הבקשות והתשובות
bgFetch.match('/ep-5.mp3').then(async (record) => {
if (!record) {
console.log('No record found');
return;
}
console.log(`Here's the request`, record.request);
const response = await record.responseReady;
console.log(`And here's the response`, response);
});
record
הוא BackgroundFetchRecord
, והוא נראה כך:
מאפיינים | |
---|---|
request |
Request הבקשה שסופקה. |
responseReady |
Promise<Response> התשובה שאוחזרה. התשובה לא מוצגת כי יכול להיות שהיא עדיין לא התקבלה. ההבטחה תידחה אם האחזור ייכשל. |
אירועים של קובץ שירות (service worker)
אירועים | |
---|---|
backgroundfetchsuccess |
כל הנתונים אוחזרו בהצלחה. |
backgroundfetchfailure |
אחת או יותר מהאחזורות נכשלו. |
backgroundfetchabort |
אחזור אחד או יותר נכשל.
האפשרות הזו שימושית בעיקר אם רוצים לנקות נתונים קשורים. |
backgroundfetchclick |
המשתמש לחץ על ממשק המשתמש של התקדמות ההורדה. |
אובייקטים של אירועים כוללים את הפרטים הבאים:
מאפיינים | |
---|---|
registration |
BackgroundFetchRegistration |
Methods | |
updateUI({ title, icons }) |
מאפשר לשנות את הכותרת או הסמלים שהגדרתם בהתחלה. הוספת התיאור היא אופציונלית, אבל היא מאפשרת לכם לספק יותר הקשר אם יש צורך. אפשר לעשות את זה רק *פעם אחת* במהלך אירועים של backgroundfetchsuccess ושל backgroundfetchfailure . |
תגובה להצלחה או לכישלון
כבר ראינו את האירוע progress
, אבל הוא שימושי רק כשהמשתמש פותח דף באתר שלכם. היתרון העיקרי של אחזור ברקע הוא שהפעולות ממשיכות לפעול גם אחרי שהמשתמש יוצא מהדף או אפילו סוגר את הדפדפן.
אם האחזור ברקע יושלם בהצלחה, ה-service worker יקבל את האירוע backgroundfetchsuccess
, ו-event.registration
יהיה רישום האחזור ברקע.
אחרי האירוע הזה, אי אפשר יותר לגשת לבקשות ולתשובות שאוחזרו, ולכן אם רוצים לשמור אותן, צריך להעביר אותן למקום אחר, כמו Cache API.
כמו ברוב האירועים של Service Worker, צריך להשתמש ב-event.waitUntil
כדי ש-Service Worker יידע מתי האירוע הושלם.
לדוגמה, ב-service worker:
addEventListener('backgroundfetchsuccess', (event) => {
const bgFetch = event.registration;
event.waitUntil(async function() {
// Create/open a cache.
const cache = await caches.open('downloads');
// Get all the records.
const records = await bgFetch.matchAll();
// Copy each request/response across.
const promises = records.map(async (record) => {
const response = await record.responseReady;
await cache.put(record.request, response);
});
// Wait for the copying to complete.
await Promise.all(promises);
// Update the progress notification.
event.updateUI({ title: 'Episode 5 ready to listen!' });
}());
});
יכול להיות שהכשל נבע משגיאת 404 אחת, שאולי לא הייתה חשובה לכם, ולכן עדיין כדאי להעתיק חלק מהתגובות למטמון כמו שמוסבר למעלה.
תגובה לקליק
אפשר ללחוץ על ממשק המשתמש שבו מוצגים התקדמות ההורדה והתוצאה. האירוע backgroundfetchclick
ב-Service Worker מאפשר לכם להגיב לזה. כמו למעלה, event.registration
יהיה רישום האחזור ברקע.
הפעולה הנפוצה שמתבצעת באירוע הזה היא פתיחת חלון:
addEventListener('backgroundfetchclick', (event) => {
const bgFetch = event.registration;
if (bgFetch.result === 'success') {
clients.openWindow('/latest-podcasts');
} else {
clients.openWindow('/download-progress');
}
});
מקורות מידע נוספים
תיקון: בגרסה קודמת של המאמר הזה, התייחסנו אל Background Fetch באופן שגוי כאל 'תקן אינטרנט'. ממשק ה-API לא נמצא כרגע בנתיב התקנים, והמפרט שלו מופיע ב-WICG כדוח טיוטה של קבוצת הקהילה.