עד עכשיו היו רק אזכורים וקטעי קוד קטנים של הממשק של Cache
.
כדי להשתמש ב-Service Workers ביעילות, חשוב לאמץ שיטה אחת או יותר לשמירה במטמון. כדי להשתמש בה צריך להכיר את הממשק של Cache
.
אסטרטגיית שמירה במטמון היא אינטראקציה בין אירוע fetch
של קובץ שירות (service worker) לבין הממשק Cache
.
אופן הכתיבה של אסטרטגיית השמירה במטמון תלוי, לדוגמה, ייתכן שעדיף לטפל בבקשות לנכסים סטטיים באופן שונה ממסמכים, וזה משפיע על אופן היצירה של אסטרטגיית השמירה במטמון.
לפני שניכנס לאסטרטגיות עצמן, בוא נדבר על הממשק של Cache
ומהו הממשק, וסקירה קצרה על כמה מהשיטות שהוא מציע לניהול מטמון של קובצי שירות (service worker).
הממשק Cache
לעומת מטמון ה-HTTP
אם לא עבדתם בעבר עם הממשק של Cache
, אולי תתפתו לחשוב שהוא זהה למטמון ה-HTTP או לפחות קשור אליו. זה לא נכון.
- הממשק של
Cache
הוא מנגנון לשמירה במטמון, שנפרד לחלוטין ממטמון ה-HTTP. - לכל הגדרת
Cache-Control
שבה אתם משתמשים כדי להשפיע על מטמון ה-HTTP אין השפעה על הנכסים שמאוחסנים בממשק שלCache
.
מומלץ להתייחס למטמון של הדפדפן כשכבת-על. מטמון ה-HTTP הוא מטמון ברמה נמוכה שמופעל על ידי צמדי מפתח/ערך עם הוראות מנוסחות בכותרות HTTP.
לעומת זאת, הממשק Cache
הוא מטמון ברמה גבוהה שמונע על ידי JavaScript API.
השיטה הזו מציעה יותר גמישות מאשר כשמשתמשים בצמדי מפתח/ערך של HTTP שהם פשוטים יחסית, והם מאפשרים אסטרטגיות של שמירה במטמון.
הנה כמה שיטות API חשובות בנוגע למטמון של קובצי שירות (service worker):
CacheStorage.open
כדי ליצור מכונה חדשה שלCache
.Cache.add
ו-Cache.put
כדי לאחסן את תגובות הרשת במטמון של קובץ השירות (service worker).Cache.match
כדי לאתר תגובה שנשמרה במטמון במכונה שלCache
.Cache.delete
כדי להסיר תגובה שנשמרה במטמון ממכונה שלCache
.
ועוד תחומים רבים. יש עוד שיטות שימושיות, אבל אלה השיטות הבסיסיות שתראו בהמשך המדריך.
האירוע הצנוע של fetch
החלק השני של אסטרטגיית השמירה במטמון הוא האירוע fetch
של קובץ השירות (service worker).
עד עכשיו שמעתם במאמר הזה על "יירוט בקשות רשת", והאירוע fetch
בתוך קובץ שירות (service worker) מתרחש:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('install', (event) => {
event.waitUntil(caches.open(cacheName));
});
self.addEventListener('fetch', async (event) => {
// Is this a request for an image?
if (event.request.destination === 'image') {
// Open the cache
event.respondWith(caches.open(cacheName).then((cache) => {
// Respond with the image from the cache or from the network
return cache.match(event.request).then((cachedResponse) => {
return cachedResponse || fetch(event.request.url).then((fetchedResponse) => {
// Add the network response to the cache for future visits.
// Note: we need to make a copy of the response to save it in
// the cache and use the original as the request response.
cache.put(event.request, fetchedResponse.clone());
// Return the network response
return fetchedResponse;
});
});
}));
} else {
return;
}
});
זו דוגמה לצעצוע, ואתם יכולים לראות אותו בעצמכם, אבל היא גם מאפשרת הצצה למה שה-Service Workers יכולים לעשות. הקוד שלמעלה מבצע את הפעולות הבאות:
- צריך לבדוק את המאפיין
destination
של הבקשה כדי לראות אם זו בקשת תמונה. - אם התמונה נמצאת במטמון של ה-Service Worker, יש להציג אותה משם. אם לא, יש לאחזר את התמונה מהרשת, לאחסן את התגובה במטמון ולהחזיר את תגובת הרשת.
- כל שאר הבקשות מועברות דרך ה-Service Worker ללא אינטראקציה עם המטמון.
האובייקט event
של אחזור מכיל מאפיין request
שכולל קטעי מידע שימושיים שעוזרים לזהות את הסוג של כל בקשה:
url
– כתובת ה-URL של בקשת הרשת שמטופלת כרגע באירועfetch
.method
– זוהי שיטת הבקשה (למשלGET
אוPOST
).mode
, שמתאר את מצב הבקשה. הערך של'navigate'
משמש לעיתים קרובות כדי להבדיל בין בקשות למסמכי HTML לבין בקשות אחרות.destination
, שמתאר את סוג התוכן המבוקש באופן שלא נעשה שימוש בסיומת הקובץ של הנכס המבוקש.
שוב, שם המשחק הוא אסינכרוני.
חשוב לזכור שהאירוע install
כולל שיטה מסוג event.waitUntil
שמבטיחה את המשך השימוש ב-method, וצריך להמתין לפתרון הבעיה לפני שממשיכים בהפעלה.
האירוע fetch
מציע שיטה דומה של
event.respondWith
שאפשר להשתמש בה כדי להחזיר את התוצאה של בקשה
אסינכרונית של
fetch
או של תגובה שמוחזרת על ידי השיטה
match
של הממשק Cache
.
אסטרטגיות לשמירה במטמון
עכשיו, אחרי שהכרתם קצת את המכונות של Cache
ואת הגורם המטפל באירועים של fetch
, תוכלו להתחיל לחקור אסטרטגיות לשמירה במטמון של קובצי שירות (service worker).
יש כמעט אינסופיות, אבל המדריך הזה יתמקד באסטרטגיות שמתאימות ל-Workbox, כך שתוכלו לקבל מושג כללי על מה שקורה ב-Workbox.
מטמון בלבד
נתחיל באסטרטגיה פשוטה של שמירה במטמון, שנקרא 'מטמון בלבד'. זה רק זה: כשה-Service Worker שולט בדף, בקשות תואמות עוברות תמיד רק למטמון. כלומר, כדי שהתבנית תפעל בצורה תקינה וצריך לשמור מראש נכסים ששמורים במטמון, הנכסים האלה אף פעם לא יעודכנו במטמון עד שה-Service Worker יעודכן.
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
// Assets to precache
const precachedAssets = [
'/possum1.jpg',
'/possum2.jpg',
'/possum3.jpg',
'/possum4.jpg'
];
self.addEventListener('install', (event) => {
// Precache assets on install
event.waitUntil(caches.open(cacheName).then((cache) => {
return cache.addAll(precachedAssets);
}));
});
self.addEventListener('fetch', (event) => {
// Is this one of our precached assets?
const url = new URL(event.request.url);
const isPrecachedRequest = precachedAssets.includes(url.pathname);
if (isPrecachedRequest) {
// Grab the precached asset from the cache
event.respondWith(caches.open(cacheName).then((cache) => {
return cache.match(event.request.url);
}));
} else {
// Go to the network
return;
}
});
למעלה, מערך של נכסים נשמר מראש בזמן ההתקנה.
כשה-Service Worker מטפל באחזורים, אנחנו בודקים אם כתובת ה-URL של הבקשה שמטופלת באירוע fetch
נמצאת במערך הנכסים שנשמרו מראש.
אם כן, אנחנו לוקחים את המשאב מהמטמון ומדלגים על הרשת.
בקשות אחרות עוברות לרשת ורק לרשת.
כדי לראות את האסטרטגיה הזו בפעולה, צפו בהדגמה הזו כשהמסוף שלכם פתוח.
רשת בלבד
הערך ההפוך ל-'Cache Only' (מטמון בלבד) הוא 'Network Only' (רשת בלבד), שבו הבקשה מועברת דרך Service Worker לרשת בלי אינטראקציה עם המטמון של ה-Service Worker. זו אסטרטגיה טובה לשמירה על עדכניות התוכן (תגי עיצוב), אבל החיסרון הוא שהיא אף פעם לא תפעל כשהמשתמש לא מחובר לאינטרנט.
כשבקשה מועברת לרשת, לא מתקשרים ל-event.respondWith
עבור בקשה תואמת.
אם רוצים להשתמש מפורשות, אפשר להוסיף return;
ריק ב-callback של האירוע fetch
עבור בקשות שרוצים להעביר לרשת.
זה מה שקורה בהדגמה של האסטרטגיה 'מטמון בלבד' לבקשות שלא נשמרות מראש.
קודם מטמון, בחזרה לרשת
האסטרטגיה הזו היא המקום שבו הדברים קצת יותר מעורבים. כשמדובר בבקשות התאמה, התהליך מתבצע כך:
- הבקשה מגיעה למטמון. אם הנכס נמצא במטמון, מציגים אותו משם.
- אם הבקשה לא במטמון, עוברים לרשת.
- כשבקשת הרשת מסתיימת, מוסיפים אותה למטמון ואז מחזירים את התגובה מהרשת.
הנה דוגמה לאסטרטגיה הזו, שאותה אפשר לבדוק בהדגמה בזמן אמת:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
// Check if this is a request for an image
if (event.request.destination === 'image') {
event.respondWith(caches.open(cacheName).then((cache) => {
// Go to the cache first
return cache.match(event.request.url).then((cachedResponse) => {
// Return a cached response if we have one
if (cachedResponse) {
return cachedResponse;
}
// Otherwise, hit the network
return fetch(event.request).then((fetchedResponse) => {
// Add the network response to the cache for later visits
cache.put(event.request, fetchedResponse.clone());
// Return the network response
return fetchedResponse;
});
});
}));
} else {
return;
}
});
אמנם הדוגמה הזו כוללת רק תמונות, אבל זוהי אסטרטגיה מצוינת להחיל על כל הנכסים הסטטיים (כמו CSS , JavaScript, תמונות וגופנים), במיוחד אלה שעברו גיבוב (hash). הוא משפר את המהירות של נכסים שלא ניתנים לשינוי על ידי ביצוע צדדי של בדיקות עדכניות של תוכן עם השרת שמטמון ה-HTTP עשוי להתחיל לפעול. חשוב מכך, כל הנכסים שנשמרו במטמון יהיו זמינים במצב אופליין.
קודם בחיבור לרשת, בחזרה למטמון
אם תפעילו את הפקודה "מטמון קודם כל רשת שנייה", תקבלו את האסטרטגיה "הרשת הראשונה היא מטמון שנייה", וכך היא נשמעת:
- תחילה נכנסים לרשת כדי לקבל בקשה, ומציבים את התגובה במטמון.
- אם אתם לא מחוברים לאינטרנט בשלב מאוחר יותר, תוכלו לחזור לגרסה האחרונה של התגובה הזו במטמון.
השיטה הזו מתאימה במיוחד לבקשות HTML או API, כשכשאתם אונליין, אתם רוצים את הגרסה העדכנית ביותר של המשאב, אבל אתם רוצים לתת גישה אופליין לגרסה העדכנית ביותר שזמינה. כך זה עשוי להיראות כשמחילים אותו על בקשות ל-HTML:
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
// Check if this is a navigation request
if (event.request.mode === 'navigate') {
// Open the cache
event.respondWith(caches.open(cacheName).then((cache) => {
// Go to the network first
return fetch(event.request.url).then((fetchedResponse) => {
cache.put(event.request, fetchedResponse.clone());
return fetchedResponse;
}).catch(() => {
// If the network is unavailable, get
return cache.match(event.request.url);
});
}));
} else {
return;
}
});
אפשר לנסות את התכונה הזו בהדגמה. תחילה עוברים לדף. ייתכן שתצטרכו לטעון מחדש כדי שתגובת ה-HTML תוצב במטמון. לאחר מכן, בכלים למפתחים, אפשר לדמות חיבור במצב אופליין ולטעון מחדש שוב. הגרסה הזמינה האחרונה תוצג באופן מיידי מהמטמון.
במצבים שבהם היכולת אופליין חשובה, אבל צריך לאזן בין היכולת הזו לבין גישה לגרסה האחרונה של מעט תגי עיצוב או נתוני API, שיטת "הרשת תחילה, שמירה במטמון" היא אסטרטגיה יציבה להשגת המטרה הזו.
לא פעיל בזמן האימות מחדש
מבין האסטרטגיות שטיפלנו בהן עד עכשיו, "Stale-time-reVerify" היא המורכבות ביותר. זו שיטה דומה לשתי האסטרטגיות האחרונות, אבל בהליך הזה ניתנת עדיפות למהירות הגישה למשאב, תוך שמירה על העדכניות שלה ברקע. אסטרטגיה זו נראית כך:
- בבקשה הראשונה לנכס, צריך לאחזר אותו מהרשת, לשמור אותו במטמון ולהחזיר את תגובת הרשת.
- בבקשות הבאות, צריך קודם להציג את הנכס מהמטמון, אחר כך 'ברקע', לבקש ממנו שוב מהרשת ולעדכן את רשומות המטמון של הנכס.
- לבקשות לאחר מכן, תתקבל הגרסה האחרונה שאוחזרה מהרשת שנשמרה במטמון בשלב הקודם.
זוהי אסטרטגיה מצוינת לדברים שכן חשוב להתעדכן בהם, אבל הם לא חיוניים. חשבו על דברים כמו דמויות באתר של מדיה חברתית. הם מתעדכנים כשהמשתמשים מגיעים לעשות זאת, אבל לא חייבים להשתמש בגרסה האחרונה בכל בקשה.
// Establish a cache name
const cacheName = 'MyFancyCacheName_v1';
self.addEventListener('fetch', (event) => {
if (event.request.destination === 'image') {
event.respondWith(caches.open(cacheName).then((cache) => {
return cache.match(event.request).then((cachedResponse) => {
const fetchedResponse = fetch(event.request).then((networkResponse) => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
return cachedResponse || fetchedResponse;
});
}));
} else {
return;
}
});
תוכלו לראות את זה בפעולה בהדגמה נוספת בשידור חי, במיוחד אם תשימו לב לכרטיסייה'רשת' בכלים למפתחים בדפדפן, ובמציג CacheStorage
של הדפדפן (אם כלי הפיתוח של הדפדפן שלכם כולל כלי כזה).
קדימה לתיבת העבודה!
זהו סיכום של בדיקת ה-API של Service Worker וממשקי API קשורים, ומשמעות הדבר היא שלמדתם מספיק איך להשתמש ישירות ב-Service Workers כדי להתחיל לטפל ב-Workbox!