คำแนะนำในการแคชที่จำเป็น

Andrew Guan
Andrew Guan

บางเว็บไซต์อาจต้องสื่อสารกับ Service Worker โดยไม่จำเป็นต้อง ทราบถึงผลลัพธ์ ตัวอย่างเช่น

  • หน้าเว็บจะส่งรายการ URL ให้โปรแกรมทำงานของบริการ ดึงข้อมูลล่วงหน้า ดังนั้นเมื่อผู้ใช้คลิก ลิงก์เอกสารหรือทรัพยากรย่อยของหน้า มีอยู่ในแคชแล้ว ไปยังส่วนต่างๆ ได้เร็วขึ้นมาก
  • หน้าเว็บจะขอให้โปรแกรมทำงานของบริการเรียกและแคชชุดบทความยอดนิยม เพื่อให้ ใช้งานแบบออฟไลน์ได้

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

แผนภาพของหน้าที่ขอทรัพยากรเพื่อแคชไปยัง Service Worker

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

เคสการผลิต

1-800-Flowers.com ใช้ Simperative Caching (การดึงข้อมูลล่วงหน้า) กับ Service Worker ผ่าน postMessage() เพื่อดึงข้อมูล รายการยอดนิยมในหน้าหมวดหมู่เพื่อให้การนำทางต่อมาไปยังหน้ารายละเอียดผลิตภัณฑ์เร็วขึ้น

โลโก้ดอกไม้ 1-800 ดอก

โดยใช้การผสมผสานระหว่างกันในการตัดสินใจว่าจะดึงข้อมูลรายการใดล่วงหน้า

  • เมื่อโหลดหน้าเว็บ จะขอให้ผู้ปฏิบัติงานบริการเรียกข้อมูล JSON สำหรับรายการ 9 อันดับแรก และ เพิ่มออบเจ็กต์การตอบสนองที่เป็นผลลัพธ์ลงในแคช
  • สำหรับรายการที่เหลือ ระบบจะฟัง mouseover ดังนั้นเมื่อ ผู้ใช้เลื่อนเคอร์เซอร์ไปวางเหนือรายการ ผู้ใช้อาจทริกเกอร์การดึงข้อมูลทรัพยากรตาม "ดีมานด์"

โดยใช้ Cache API เพื่อจัดเก็บ JSON คำตอบ:

วันที่ โลโก้ดอกไม้ 1-800 ดอก
การดึงข้อมูลผลิตภัณฑ์ JSON ล่วงหน้าจากหน้าข้อมูลผลิตภัณฑ์ที่แสดงใน 1-800Flowers.com

เมื่อผู้ใช้คลิกที่รายการหนึ่งๆ จะสามารถดึงข้อมูล JSON ที่เชื่อมโยงกับรายการนั้นจากแคช โดยไม่จำเป็นต้องไปที่เครือข่าย ทำให้การนำทางรวดเร็วขึ้น

การใช้ Workbox

กล่องงานช่วยให้คุณส่งข้อความไปยัง Service Worker จากแพ็กเกจ workbox-window ซึ่งเป็นชุดโมดูล ที่จะเรียกใช้ในบริบทของหน้าต่าง วิธีนี้เป็นส่วนเติมเต็มสำหรับแพ็กเกจ Workbox อื่นๆ ที่ทำงานใน Service Worker

หากต้องการสื่อสารหน้าเว็บกับ Service Worker ก่อนอื่นให้รับการอ้างอิงออบเจ็กต์ Workbox ไปยัง Service Worker ที่ลงทะเบียน:

const wb = new Workbox('/sw.js');
wb.register();

คุณก็สามารถส่งข้อความได้โดยตรง โดยไม่ต้องยุ่งยากกับการต้อง การลงทะเบียน การตรวจสอบการเปิดใช้งาน หรือการพิจารณา API การสื่อสารพื้นฐาน:

wb.messageSW({"type": "PREFETCH", "payload": {"urls": ["/data1.json", "data2.json"]}}); });

โปรแกรมทำงานของบริการจะใช้เครื่องจัดการ message เพื่อ ฟังข้อความเหล่านี้ หรืออาจใช้ตอบกลับ แต่ในกรณีเช่นนี้ ไม่จำเป็น:

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PREFETCH') {
    // do something
  }
});

การใช้ API ของเบราว์เซอร์

หากไลบรารี Workbox ไม่เพียงพอสำหรับความต้องการของคุณ ต่อไปนี้เป็นวิธีการใช้หน้าต่างเพื่อการให้บริการ การสื่อสารกับพนักงาน โดยใช้ API ของเบราว์เซอร์

postMessage API ซึ่งใช้เพื่อสร้างกลไกการสื่อสารแบบทางเดียวจากหน้าเว็บไปยังโปรแกรมทำงานของบริการได้

หน้าเว็บเรียก postMessage() ใน อินเทอร์เฟซของโปรแกรมทำงานของบริการ:

navigator.serviceWorker.controller.postMessage({
  type: 'MSG_ID',
  payload: 'some data to perform the task',
});

โปรแกรมทำงานของบริการจะใช้เครื่องจัดการ message เพื่อ ฟังข้อความเหล่านี้

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === MSG_ID) {
    // do something
  }
});

คุณไม่จำเป็นต้องระบุแอตทริบิวต์ {type : 'MSG_ID'} โดยเด็ดขาด แต่แอตทริบิวต์ดังกล่าวเป็นวิธีหนึ่งที่ทำให้หน้าเว็บทำสิ่งต่อไปนี้ได้ ส่งคำสั่งประเภทต่างๆ ไปยัง Service Worker (ซึ่งก็คือ "เพื่อดึงข้อมูลล่วงหน้า" และ "เพื่อล้าง" พื้นที่เก็บข้อมูล") โปรแกรมทำงานของบริการอาจแตกแขนงไปยังเส้นทางการดำเนินการต่างๆ โดยอิงตามแฟล็กนี้

หากการดำเนินการสำเร็จ ผู้ใช้จะได้รับประโยชน์จากการทำงานดังกล่าว แต่หากไม่ ก็จะไม่เปลี่ยนแปลงขั้นตอนของผู้ใช้หลัก ตัวอย่างเช่น เมื่อ 1-800-Flowers.com พยายามแคชล่วงหน้า หน้าเว็บไม่จำเป็นต้องทราบว่า Service Worker สำเร็จหรือไม่ หากใช่ ผู้ใช้จะสามารถไปยังส่วนต่างๆ ได้เร็วขึ้น หากไม่มี หน้าเว็บยังคงต้องไปยังหน้าใหม่ อาจใช้เวลานานขึ้นเล็กน้อย

ตัวอย่างง่ายๆ ที่ดึงข้อมูลล่วงหน้า

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

การใช้การดึงข้อมูลล่วงหน้าในเว็บไซต์ทำได้หลายวิธี ดังนี้

สำหรับสถานการณ์การดึงข้อมูลล่วงหน้าที่ค่อนข้างง่าย เช่น การดึงข้อมูลเอกสารล่วงหน้า หรือเนื้อหาที่เจาะจง (JS, CSS และอื่นๆ) เทคนิคเหล่านั้นเป็นวิธีที่ดีที่สุด

หากต้องใช้ตรรกะเพิ่มเติม เช่น การแยกวิเคราะห์ทรัพยากรการดึงข้อมูลล่วงหน้า (ไฟล์ JSON หรือหน้าเว็บ) ใน ในการดึงข้อมูล URL ภายใน การมอบหมายงานนี้ทั้งหมดให้กับ Service Worker

การมอบสิทธิ์การดำเนินการประเภทนี้ให้กับโปรแกรมทำงานของบริการมีข้อดีดังต่อไปนี้

  • ลดภาระในการดึงข้อมูลและการประมวลผลหลังการดึงข้อมูล (ซึ่งจะแนะนำ ในภายหลัง) ไปยังชุดข้อความรอง การทำเช่นนี้จะช่วยให้เทรดหลักจัดการกับเทรดหลักที่สำคัญกว่าได้ เช่น การตอบสนองการโต้ตอบของผู้ใช้
  • ทำให้ไคลเอ็นต์หลายตัว (เช่น แท็บต่างๆ) สามารถใช้ฟังก์ชันการทำงานร่วมกันซ้ำได้ และแม้กระทั่งการเรียกใช้ บริการพร้อมกันโดยไม่บล็อกเทรดหลัก

ดึงข้อมูลหน้ารายละเอียดผลิตภัณฑ์ล่วงหน้า

ใช้ postMessage() ครั้งแรกใน อินเทอร์เฟซโปรแกรมทำงานของบริการ (Service Worker) และส่งอาร์เรย์ URL ไปยังแคช ดังนี้

navigator.serviceWorker.controller.postMessage({
  type: 'PREFETCH',
  payload: {
    urls: [
      'www.exmaple.com/apis/data_1.json',
      'www.exmaple.com/apis/data_2.json',
    ],
  },
});

ใน Service Worker ให้ใช้เครื่องจัดการ message เพื่อ ดักจับและประมวลผลข้อความที่ส่งจากแท็บที่ใช้งานอยู่:

addEventListener('message', (event) => {
  let data = event.data;
  if (data && data.type === 'PREFETCH') {
    let urls = data.payload.urls;
    for (let i in urls) {
      fetchAsync(urls[i]);
    }
  }
});

ในโค้ดก่อนหน้านี้ เราได้แนะนำฟังก์ชันตัวช่วยขนาดเล็กที่ชื่อ fetchAsync() เพื่อทำซ้ำใน อาร์เรย์ของ URL และส่งคำขอดึงข้อมูลสำหรับแต่ละ URL:

async function fetchAsync(url) {
  // await response of fetch call
  let prefetched = await fetch(url);
  // (optionally) cache resources in the service worker storage
}

เมื่อได้รับคำตอบแล้ว คุณสามารถใช้ส่วนหัวการแคชของแหล่งข้อมูลได้ ในหลายกรณี แต่เช่นเดียวกับหน้ารายละเอียดผลิตภัณฑ์ ทรัพยากรจะไม่ถูกแคช (ซึ่งหมายความว่าทรัพยากรเหล่านั้นจะมี ส่วนหัว Cache-control ของ no-cache) ในกรณีเช่นนี้ คุณสามารถลบล้างลักษณะการทำงานนี้ได้โดย จัดเก็บทรัพยากรที่ดึงมาในแคชของ Service Worker ซึ่งมีประโยชน์เพิ่มเติมที่ทำให้ เพื่อใช้ในสถานการณ์ออฟไลน์

นอกเหนือไปจากข้อมูล JSON

เมื่อดึงข้อมูล JSON มาจากปลายทางเซิร์ฟเวอร์ ข้อมูลมักจะมี URL อื่นๆ ที่ ที่ควรดึงข้อมูลล่วงหน้า เช่น รูปภาพหรือข้อมูลปลายทางอื่นๆ ที่เชื่อมโยงกับระดับที่ 1 นี้

สมมติว่าในตัวอย่างของเรา ข้อมูล JSON ที่แสดงเป็นข้อมูลของเว็บไซต์ขายของชำ

{
  "productName": "banana",
  "productPic": "https://cdn.example.com/product_images/banana.jpeg",
  "unitPrice": "1.99"
 }

แก้ไขโค้ด fetchAsync() เพื่อทำซ้ำในรายการผลิตภัณฑ์และแคชรูปภาพหลักสำหรับ แต่ละแบบ ได้แก่

async function fetchAsync(url, postProcess) {
  // await response of fetch call
  let prefetched = await fetch(url);

  //(optionally) cache resource in the service worker cache

  // carry out the post fetch process if supplied
  if (postProcess) {
    await postProcess(prefetched);
  }
}

async function postProcess(prefetched) {
  let productJson = await prefetched.json();
  if (productJson && productJson.product_pic) {
    fetchAsync(productJson.product_pic);
  }
}

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

บทสรุป

ในบทความนี้ เราพูดถึงกรณีการใช้งานที่พบบ่อยของการสื่อสารทางเดียวระหว่างหน้าเว็บและบริการ ผู้ปฏิบัติงาน: การแคชที่จำเป็น ตัวอย่างที่พูดถึงนี้มีวัตถุประสงค์เพื่อแสดงให้ เห็นถึงวิธี โดยใช้รูปแบบนี้ และวิธีการเดียวกันนี้ก็สามารถนำไปใช้กับกรณีการใช้งานอื่นๆ ได้เช่นกัน เช่น การแคชบทความยอดนิยมตามความต้องการสำหรับการใช้งานแบบออฟไลน์ การบุ๊กมาร์ก และอื่นๆ

สำหรับรูปแบบเพิ่มเติมของการสื่อสารของหน้าเว็บและ Service Worker โปรดดูที่

  • อัปเดตการออกอากาศ: เรียกใช้หน้าเว็บจาก Service Worker เพื่อแจ้ง เกี่ยวกับอัปเดตที่สำคัญ (เช่น เว็บแอปเวอร์ชันใหม่พร้อมใช้งาน)
  • การสื่อสารแบบ 2 ทาง: การมอบสิทธิ์งานให้กับ Service Worker (เช่น มีการดาวน์โหลดข้อมูลจำนวนมาก) และคอยอัปเดตหน้าเว็บเกี่ยวกับความคืบหน้า