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

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

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

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

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

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

const cacheAvailable = 'caches' in self;

การรองรับเบราว์เซอร์

  • Chrome: 40
  • ขอบ: 16
  • Firefox: 41
  • Safari: 11.1

แหล่งที่มา

คุณสามารถเข้าถึง 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() แต่ใช้เวลา อาร์เรย์ของออบเจ็กต์หรือ URL Request รายการ (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 หากไม่พบ

ในการพิจารณาว่า 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() สำหรับแต่ละแคช

กำลังค้นหา

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