Cache API: คู่มือฉบับย่อ

ดูวิธีใช้ Cache API เพื่อให้ข้อมูลแอปพลิเคชันพร้อมใช้งานแบบออฟไลน์

Cache API เป็นระบบสำหรับจัดเก็บและเรียกข้อมูลคําขอเครือข่ายและการตอบกลับที่เกี่ยวข้อง ซึ่งอาจเป็นคําขอและคําตอบปกติที่สร้างในระหว่างการเรียกใช้แอปพลิเคชัน หรืออาจสร้างขึ้นเพื่อวัตถุประสงค์ในการเก็บข้อมูลไว้ใช้ภายหลังเท่านั้น

Cache API สร้างขึ้นเพื่อให้ Service Worker แคชคำขอเครือข่ายได้เพื่อให้สามารถตอบกลับได้อย่างรวดเร็ว ไม่ว่าจะมีความเร็วหรือความพร้อมของเครือข่ายเพียงใด อย่างไรก็ตาม คุณยังใช้ API นี้เป็นกลไกการจัดเก็บข้อมูลทั่วไปได้ด้วย

ฟีเจอร์นี้พร้อมให้บริการที่ไหนบ้าง

Cache API พร้อมใช้งานในเบราว์เซอร์สมัยใหม่ทั้งหมด โดย API นี้จะแสดงผ่านพร็อพเพอร์ตี้ caches ทั่วโลก คุณจึงทดสอบว่ามี API นี้อยู่หรือไม่ได้ด้วยการตรวจหาฟีเจอร์ง่ายๆ ดังนี้

const cacheAvailable = 'caches' in self; 

Browser Support

  • Chrome: 40.
  • Edge: 16.
  • Firefox: 41.
  • Safari: 11.1.

Source

คุณเข้าถึง Cache API ได้จากหน้าต่าง, iframe, Worker หรือ Service Worker

สิ่งที่จัดเก็บได้

แคชจะจัดเก็บเฉพาะคู่ออบเจ็กต์ Request และ Response ซึ่งแสดงถึงคำขอและการตอบกลับ HTTP ตามลำดับ อย่างไรก็ตาม คําขอและการตอบกลับอาจมีข้อมูลประเภทใดก็ได้ที่โอนผ่าน HTTP ได้

เก็บข้อมูลได้เท่าใด

กล่าวโดยย่อคือ มาก อย่างน้อย 2-3 ร้อยเมกะไบต์ และอาจมากถึงหลายร้อยกิกะไบต์ขึ้นไป การใช้งานเบราว์เซอร์จะแตกต่างกันไป แต่โดยทั่วไปแล้วปริมาณพื้นที่เก็บข้อมูลที่มีอยู่จะขึ้นอยู่กับปริมาณพื้นที่เก็บข้อมูลที่มีอยู่ในอุปกรณ์

การสร้างและเปิดแคช

หากต้องการเปิดแคช ให้ใช้เมธอด 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() แต่ใช้อาร์เรย์ของออบเจ็กต์ Request หรือ URL (string) ซึ่งทํางานคล้ายกับการเรียก cache.add สําหรับคําขอแต่ละรายการ ยกเว้นว่า Promise จะปฏิเสธหากไม่มีการแคชคําขอใดก็ตาม

const urls = ['/weather/today.json', '/weather/tomorrow.json']; cache.addAll(urls); 

ในแต่ละกรณีเหล่านี้ รายการใหม่จะเขียนทับรายการที่มีอยู่ซึ่งตรงกัน ซึ่งจะใช้กฎการจับคู่เดียวกันกับที่อธิบายไว้ในส่วนการดึงข้อมูล

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 ในกรณีอื่นๆ

เบราว์เซอร์จะใช้ข้อมูลมากกว่าแค่ URL เพื่อพิจารณาว่า Requests 2 รายการตรงกันหรือไม่ ระบบจะถือว่าคำขอ 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