บางเว็บไซต์อาจต้องสื่อสารกับ Service Worker โดยไม่จำเป็นต้อง ทราบถึงผลลัพธ์ ตัวอย่างเช่น
- หน้าเว็บจะส่งรายการ URL ให้โปรแกรมทำงานของบริการ ดึงข้อมูลล่วงหน้า ดังนั้นเมื่อผู้ใช้คลิก ลิงก์เอกสารหรือทรัพยากรย่อยของหน้า มีอยู่ในแคชแล้ว ไปยังส่วนต่างๆ ได้เร็วขึ้นมาก
- หน้าเว็บจะขอให้โปรแกรมทำงานของบริการเรียกและแคชชุดบทความยอดนิยม เพื่อให้ ใช้งานแบบออฟไลน์ได้
การมอบสิทธิ์งานที่ไม่สำคัญประเภทนี้ให้กับโปรแกรมทำงานของบริการมีประโยชน์ในการเพิ่มพื้นที่ว่าง เทรดหลักเพื่อให้จัดการงานที่เร่งด่วนได้ดียิ่งขึ้น เช่น การตอบกลับการโต้ตอบของผู้ใช้
ในคู่มือนี้ เราจะสํารวจวิธีใช้เทคนิคการสื่อสารทางเดียวจากหน้าเว็บเพื่อ โปรแกรมทำงานของบริการโดยใช้ API เบราว์เซอร์มาตรฐานและไลบรารี Workbox เราจะเรียกประเภทของ การแคชที่จำเป็น
เคสการผลิต
1-800-Flowers.com ใช้ Simperative Caching (การดึงข้อมูลล่วงหน้า) กับ Service Worker ผ่าน
postMessage()
เพื่อดึงข้อมูล
รายการยอดนิยมในหน้าหมวดหมู่เพื่อให้การนำทางต่อมาไปยังหน้ารายละเอียดผลิตภัณฑ์เร็วขึ้น
โดยใช้การผสมผสานระหว่างกันในการตัดสินใจว่าจะดึงข้อมูลรายการใดล่วงหน้า
- เมื่อโหลดหน้าเว็บ จะขอให้ผู้ปฏิบัติงานบริการเรียกข้อมูล JSON สำหรับรายการ 9 อันดับแรก และ เพิ่มออบเจ็กต์การตอบสนองที่เป็นผลลัพธ์ลงในแคช
- สำหรับรายการที่เหลือ ระบบจะฟัง
mouseover
ดังนั้นเมื่อ ผู้ใช้เลื่อนเคอร์เซอร์ไปวางเหนือรายการ ผู้ใช้อาจทริกเกอร์การดึงข้อมูลทรัพยากรตาม "ดีมานด์"
โดยใช้ Cache API เพื่อจัดเก็บ JSON คำตอบ:
เมื่อผู้ใช้คลิกที่รายการหนึ่งๆ จะสามารถดึงข้อมูล 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 ดังกล่าวเพื่อให้การนำทางรวดเร็วขึ้น
การใช้การดึงข้อมูลล่วงหน้าในเว็บไซต์ทำได้หลายวิธี ดังนี้
- การใช้ลิงก์แท็กการดึงข้อมูลล่วงหน้าในหน้า: ทรัพยากรจะถูกเก็บไว้ใน
แคชของเบราว์เซอร์เป็นเวลา 5 นาที หลังจากนั้นกฎ
Cache-Control
ปกติสำหรับทรัพยากร นำไปใช้ - การเสริมเทคนิคก่อนหน้าด้วยกลยุทธ์การแคชรันไทม์ในบริการ ของผู้ปฏิบัติงานเพื่อยืดอายุการใช้งานของการดึงข้อมูลล่วงหน้า ทรัพยากรเกินขีดจำกัดนี้
สำหรับสถานการณ์การดึงข้อมูลล่วงหน้าที่ค่อนข้างง่าย เช่น การดึงข้อมูลเอกสารล่วงหน้า หรือเนื้อหาที่เจาะจง (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 (เช่น มีการดาวน์โหลดข้อมูลจำนวนมาก) และคอยอัปเดตหน้าเว็บเกี่ยวกับความคืบหน้า