ดูวิธีใช้ Cache API เพื่อทำให้ข้อมูลแอปพลิเคชันพร้อมใช้งานแบบออฟไลน์
Cache API เป็นระบบสำหรับจัดเก็บและเรียกข้อมูลคำขอของเครือข่ายและการตอบกลับที่เกี่ยวข้อง โดยอาจเป็นคำขอและคำตอบทั่วไปที่สร้างขึ้นในระหว่างที่แอปพลิเคชันทำงาน หรือสร้างขึ้นเพื่อวัตถุประสงค์ในการจัดเก็บข้อมูลไว้ใช้ภายหลังเท่านั้น
Cache API สร้างขึ้นเพื่ออนุญาตให้โปรแกรมทำงานของบริการแคชคำขอของเครือข่ายเพื่อให้ตอบสนองได้อย่างรวดเร็ว โดยไม่คำนึงถึงความเร็วหรือความพร้อมใช้งานของเครือข่าย อย่างไรก็ตาม สามารถใช้ API เป็นกลไกการเก็บข้อมูลทั่วไปได้เช่นกัน
พร้อมให้บริการที่ไหนบ้าง
Cache API พร้อมใช้งานในเบราว์เซอร์ที่ทันสมัยทั้งหมด จะแสดงผ่านพร็อพเพอร์ตี้ caches
ส่วนกลาง เพื่อให้คุณทดสอบการมีอยู่ของ API ได้ด้วยการตรวจจับฟีเจอร์ง่ายๆ ดังนี้
const cacheAvailable = 'caches' in self;
คุณเข้าถึง Cache API ได้จากหน้าต่าง, iframe, ผู้ปฏิบัติงาน หรือ Service Worker
สิ่งที่จัดเก็บได้
แคชจะจัดเก็บเฉพาะคู่ของออบเจ็กต์ Request
และ Response
โดยจะแสดงคำขอ HTTP และการตอบกลับตามลำดับ อย่างไรก็ตาม คำขอและคำตอบอาจมีข้อมูลประเภทใดก็ตามที่โอนผ่าน HTTP ได้
สามารถจัดเก็บได้จำนวนเท่าใด
โดยสรุปคือมาก อย่างน้อย 200-200 เมกะไบต์ และอาจมีขนาดหลายร้อยกิกะไบต์ขึ้นไป การใช้งานเบราว์เซอร์จะแตกต่างกันไป แต่ปริมาณพื้นที่เก็บข้อมูลที่ใช้ได้จะขึ้นอยู่กับปริมาณพื้นที่เก็บข้อมูลที่ใช้ได้ในอุปกรณ์
การสร้างและเปิดแคช
หากต้องการเปิดแคช ให้ใช้เมธอด caches.open(name)
โดยการส่งชื่อแคชเป็นพารามิเตอร์เดียว หากไม่มีแคชที่มีชื่ออยู่ ระบบจะสร้างแคชนั้นขึ้น เมธอดนี้จะแสดงผล Promise
ที่แปลค่าด้วยออบเจ็กต์ Cache
const cache = await caches.open('my-cache');
// do something with cache...
การเพิ่มในแคช
การเพิ่มรายการไปยังแคชมี 3 วิธี คือ add
, addAll
และ put
ทั้ง 3 วิธีจะแสดงผล Promise
cache.add
ตัวเลือกแรกคือ cache.add()
โดยใช้พารามิเตอร์ 1 รายการ ซึ่งอาจเป็น 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()
แต่จะใช้อาร์เรย์ของออบเจ็กต์หรือ URL Request
รายการ (string
s) ซึ่งทำงานคล้ายกับการเรียกใช้ cache.add
สำหรับคำขอแต่ละรายการ ยกเว้นว่า Promise
จะปฏิเสธหากไม่มีการแคชคำขอ 1 รายการ
const urls = ['/weather/today.json', '/weather/tomorrow.json'];
cache.addAll(urls);
ในแต่ละกรณีเหล่านี้ รายการใหม่จะแทนที่รายการที่มีอยู่ที่ตรงกัน การดำเนินการนี้จะใช้กฎการจับคู่แบบเดียวกับที่อธิบายไว้ในส่วนretrieving
cache.put
ประการสุดท้ายคือ cache.put()
ซึ่งช่วยให้คุณจัดเก็บการตอบกลับจากเครือข่าย หรือสร้างและจัดเก็บ Response
ของคุณเองก็ได้ ต้องใช้พารามิเตอร์ 2 ตัว รายการแรกอาจเป็นออบเจ็กต์ Request
หรือ URL (string
) รายการที่ 2 ต้องเป็น 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');
การทำงานกับออบเจ็กต์การตอบกลับ
ตัวสร้างออบเจ็กต์ 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
2 ค่าตรงกันหรือไม่ เบราว์เซอร์จะใช้มากกว่า URL เพียงอย่างเดียว ระบบจะถือว่าคำขอ 2 รายการแตกต่างกันหากมีสตริงการค้นหา ส่วนหัว Vary
หรือเมธอด HTTP แตกต่างกัน (GET
, POST
, PUT
เป็นต้น)
คุณจะข้ามสิ่งเหล่านี้บางส่วนหรือทั้งหมดได้โดยส่งออบเจ็กต์ตัวเลือกเป็นพารามิเตอร์ที่ 2
const options = {
ignoreSearch: true,
ignoreMethod: true,
ignoreVary: true
};
const response = await cache.match(request, options);
// do something with the response
หากมีคำขอที่แคชไว้มากกว่า 1 รายการ ระบบจะแสดงผลคำขอที่สร้างก่อน หากต้องการเรียกคำตอบที่ตรงกันทั้งหมด ให้ใช้ 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