במאמר הזה מוסבר איך משתמשים ב-Cache API כדי שנתוני האפליקציות שלכם יהיו זמינים במצב אופליין.
Cache API הוא מערכת לאחסון ולאחזור רשת הבקשות והתשובות התואמות שלהן. יכול להיות שאלה בקשות רגילות והתגובות שנוצרות במהלך הרצת האפליקציה, או שהן עשויות אך ורק למטרת אחסון נתונים לשימוש מאוחר יותר.
Cache API נוצר כדי לאפשר ל-Service Workers לשמור בקשות רשת במטמון כך שיוכלו לספק תגובות מהירות, ללא קשר למהירות הרשת זמינות. עם זאת, ניתן להשתמש בממשק ה-API גם כמנגנון אחסון כללי.
איפה השירות זמין?
Cache API זמין בכל הדפדפנים המתקדמים. זה כן
נחשפו דרך הנכס הגלובלי caches
, כך שאפשר לבדוק נוכחות של
באמצעות זיהוי תכונות פשוט:
const cacheAvailable = 'caches' in self;
ניתן לגשת ל-Cache API מחלון, מ-iframe, מ-worker או מ-service worker.
מה אפשר לאחסן
במטמון מאוחסנים רק צמדים של Request
ו-
Response
אובייקטים, שמייצגים בקשות ותגובות של HTTP,
בהתאמה. עם זאת, הבקשות והתשובות יכולות להכיל כל סוג של נתונים.
שאפשר להעביר באמצעות HTTP.
כמה אפשר לאחסן?
בקיצור, הרבה, לפחות כמה מאות מגה-בייט, מאות ג'יגה בייט או יותר. יישומי הדפדפן משתנים, אבל הכמות בדרך כלל מבוסס על נפח האחסון הזמין במכשיר.
יצירה ופתיחה של מטמון
כדי לפתוח מטמון, משתמשים בשיטה caches.open(name)
ומעבירים את השם של
את המטמון בתור פרמטר יחיד. אם המטמון בעל השם לא קיים, כנראה
נוצר. ה-method הזה מחזירה Promise
שמתרחשת עם האובייקט Cache
.
const cache = await caches.open('my-cache');
// do something with cache...
הוספה למטמון
יש שלוש דרכים להוסיף פריט למטמון – add
, addAll
ו-put
.
בכל שלוש השיטות מוחזרות Promise
.
cache.add
קודם כל, יש cache.add()
. היא מקבלת פרמטר אחד, Request
או כתובת URL (string
). היא שולחת בקשה לרשת ושומרת את התגובה
במטמון. אם
האחזור נכשל, או אם קוד הסטטוס של התשובה הוא לא בטווח ה-200,
שום דבר לא יישמר וה-Promise
דוחה. שימו לב שמעבר למקורות
אי אפשר לשמור בקשות שלא במצב CORS כי הן מחזירות status
0
. אפשר לאחסן בקשות כאלה רק באמצעות put
.
// Retreive data.json from the server and store the response.
cache.add(new Request('/data.json'));
// Retreive data.json from the server and store the response.
cache.add('/data.json');
cache.addAll
השלב הבא הוא cache.addAll()
. היא פועלת באופן דומה ל-add()
, אבל לוקחת
מערך של Request
אובייקטים או כתובות URL (string
s). אופן הפעולה הזה דומה
קריאה ל-cache.add
בכל בקשה בנפרד, מלבד הPromise
המערכת דוחה אם בקשה יחידה לא נשמרת במטמון.
const urls = ['/weather/today.json', '/weather/tomorrow.json'];
cache.addAll(urls);
בכל אחד מהמקרים האלו, רשומה חדשה מחליפה כל רשומה קיימת תואמת. לשם כך צריך להשתמש באותם כללי ההתאמה שמתוארים בקטע על אחזור.
cache.put
לבסוף, יש את cache.put()
, שמאפשר לשמור כל אחת מהתגובות
מהרשת, או ליצור ולאחסן Response
משלכם. נדרשות שתיים
. הראשונה יכולה להיות אובייקט Request
או כתובת URL (string
).
המספר השני חייב להיות Response
, מהרשת או שנוצר על ידי
// Retrieve data.json from the server and store the response.
cache.put('/data.json');
// Create a new entry for test.json and store the newly created response.
cache.put('/test.json', new Response('{"foo": "bar"}'));
// Retrieve data.json from the 3rd party site and store the response.
cache.put('https://example.com/data.json');
השיטה put()
יותר מתירנית מאשר add()
או addAll()
, וגם
תאפשר לשמור תשובות שלא קשורות ל-CORS, או תשובות אחרות שבהן הסטטוס
קוד התגובה הוא לא בטווח ה-200. היא תחליף כל קוד קודם
תגובות לאותה בקשה.
יצירת אובייקטים של בקשות
יוצרים את האובייקט Request
באמצעות כתובת ה-URL של הפריט שמאוחסן:
const request = new Request('/my-data-store/item-id');
עבודה עם אובייקטים של תגובה
ב-constructor של האובייקטים Response
מקבל סוגים רבים של נתונים, כולל
אובייקטים מסוג Blob
, ArrayBuffer
, FormData
אובייקטים ומחרוזות.
const imageBlob = new Blob([data], {type: 'image/jpeg'});
const imageResponse = new Response(imageBlob);
const stringResponse = new Response('Hello world');
אפשר להגדיר את סוג MIME של Response
על ידי הגדרת הכותרת המתאימה.
const options = {
headers: {
'Content-Type': 'application/json'
}
}
const jsonResponse = new Response('{}', options);
אם אחזרת Response
וברצונך לגשת לגוף שלו, יש
תוכלו להשתמש בכמה שיטות עזר. כל אחת מחזירה Promise
שמקודד
עם ערך מסוג אחר.
שיטה | תיאור |
---|---|
arrayBuffer |
הפונקציה מחזירה ArrayBuffer שמכיל את הגוף, עם סריאליזציה ל-
בייטים.
|
blob |
הפונקציה מחזירה את הערך Blob . אם השדה Response נוצר
עם Blob , אז ל-Blob החדש יש
מהסוג הזה. אחרת, Content-Type של
נעשה שימוש ב-Response .
|
text |
הפונקציה מפרשת את הבייטים של הגוף כמחרוזת בקידוד UTF-8. |
json |
הפונקציה מפרשת את הבייטים של הגוף כמחרוזת בקידוד UTF-8, ואז מנסה
כדי לנתח אותו כקובץ JSON. מחזירה את האובייקט שנוצר, או זורקת
TypeError אם אי אפשר לנתח את המחרוזת כ-JSON.
|
formData |
מפרש את הבייטים של הגוף כצורת HTML, המקודד כך
multipart/form-data או
application/x-www-form-urlencoded . הפונקציה מחזירה את
FormData
אובייקט, או יקפיץ ערך TypeError אם לא ניתן לנתח את הנתונים.
|
body |
מחזיר ReadableStream לנתוני הגוף. |
לדוגמה
const response = new Response('Hello world');
const buffer = await response.arrayBuffer();
console.log(new Uint8Array(buffer));
// Uint8Array(11) [72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
אחזור מהמטמון
כדי למצוא פריט במטמון, אפשר להשתמש בשיטה match
.
const response = await cache.match(request);
console.log(request, response);
אם המחרוזת request
היא מחרוזת, הדפדפן ממיר אותה ל-Request
באמצעות קריאה
new Request(request)
. הפונקציה מחזירה Promise
שמפנה ל-
Response
אם נמצאה רשומה תואמת, או undefined
אחרת.
כדי לקבוע אם שתי התאמות של Requests
תואמות, הדפדפן משתמש באפשרויות נוספות מלבד כתובת ה-URL. שתי דלתות
בקשות נחשבות שונות אם יש להן מחרוזות שאילתה שונות,
Vary
כותרות או methods של HTTP (GET
, POST
, PUT
וכו').
אפשר להתעלם מחלק מהדברים האלה או מכולם על ידי העברת אובייקט אפשרויות בתור אובייקט הפרמטר השני.
const options = {
ignoreSearch: true,
ignoreMethod: true,
ignoreVary: true
};
const response = await cache.match(request, options);
// do something with the response
אם יש התאמה ליותר מבקשה אחת במטמון, אז הבקשה שנוצרה ראשונה היא
הוחזרו. אם רוצים לאחזר את כל התשובות התואמות, אפשר להשתמש
cache.matchAll()
.
const options = {
ignoreSearch: true,
ignoreMethod: true,
ignoreVary: true
};
const responses = await cache.matchAll(request, options);
console.log(`There are ${responses.length} matching responses.`);
כקיצור דרך, אפשר לחפש בכל המטמון בבת אחת באמצעות caches.match()
במקום לקרוא ל-cache.match()
לכל מטמון.
מחפש
Cache API לא מאפשר לחפש בקשות או תגובות
חוץ מרשומות תואמות מול אובייקט Response
. אבל אפשר
להטמיע חיפוש משלכם באמצעות סינון או יצירת אינדקס.
סינון
אחת הדרכים ליישם חיפוש משלכם היא לחזור על כל הערכים
לסנן לפי האפשרויות הרצויות. נניח שאתם רוצים למצוא את כל
פריטים עם כתובות URL שמסתיימות ב-.png
.
async function findImages() {
// Get a list of all of the caches for this origin
const cacheNames = await caches.keys();
const result = [];
for (const name of cacheNames) {
// Open the cache
const cache = await caches.open(name);
// Get a list of entries. Each item is a Request object
for (const request of await cache.keys()) {
// If the request URL matches, add the response to the result
if (request.url.endsWith('.png')) {
result.push(await cache.match(request));
}
}
}
return result;
}
כך אפשר להשתמש בכל מאפיין של האובייקטים Request
ו-Response
כדי
לסנן את הרשומות. לתשומת ליבך, אם מבצעים חיפוש על קבוצות גדולות של נתונים, הפעולה תהיה איטית
.
יצירת אינדקס
הדרך השנייה ליישם חיפוש משלכם היא לנהל אינדקס נפרד של רשומות שאפשר לחפש ולאחסן ב-IndexedDB. מאחר שסוג כזה פעולה ש-indexedDB תוכנן בשביל שיש לה ביצועים הרבה יותר טובים עם מספר רב של רשומות.
אם אתם מאחסנים את כתובת ה-URL של Request
לצד המאפיינים שזמינים לחיפוש
תוכלו לאחזר בקלות את רשומת המטמון הנכונה לאחר ביצוע החיפוש.
מחיקת פריט
כדי למחוק פריט ממטמון:
cache.delete(request);
הבקשה יכולה להיות מחרוזת של Request
או של כתובת URL. השיטה הזו גם לוקחת את
זהה לאובייקט cache.match
, שמאפשר למחוק כמה
Request
/Response
צמדים לאותה כתובת URL.
cache.delete('/example/file.txt', {ignoreVary: true, ignoreSearch: true});
מחיקת מטמון
כדי למחוק מטמון, צריך להתקשר אל caches.delete(name)
. הפונקציה הזו מחזירה
Promise
ששווה ל-true
אם המטמון היה קיים ונמחק, או
false
אם לא.
תודה
תודה ל-Mat Scales שכתב את הגרסה המקורית של המאמר הזה, הופיעו לראשונה ב-WebFundamentals.