วิดีโอเป็นชิ้นงานที่จัดการได้ยาก การสตรีมต้องใช้แบนด์วิดท์จำนวนมาก และการแคชก็ไม่ใช่เรื่องง่าย ปัญหาเหล่านี้จะยิ่งรุนแรงขึ้นเมื่อวิดีโอเล่นซ้ำ เช่น ในจอแสดงผลคีออส ตัวอย่างเช่น หากบริษัทมีอุปกรณ์หลายร้อยเครื่องที่เล่นวิดีโอ 30 รายการซ้ำๆ ตลอดทั้งวันทุกวัน ก็อาจทำให้เครือข่ายของบริษัททำงานหนักเกินไปได้อย่างรวดเร็ว การแสดงวิดีโอจากแคชแทนการสตรีมจะทำให้คุณเสียค่าใช้จ่ายในการดาวน์โหลดเพียงครั้งเดียว เล่นวิดีโอครั้งต่อๆ ไปได้เร็วขึ้น และทำให้วิดีโอพร้อมให้เล่นแบบออฟไลน์ หากต้องการทำเช่นนี้ คุณสามารถใช้ประโยชน์จากความสามารถในการจัดเก็บข้อมูลของเบราว์เซอร์ ซึ่ง Cache Storage API และ IndexedDB เหมาะสมที่สุดในการจัดเก็บไฟล์วิดีโอ แม้ว่าทั้ง 2 ตัวเลือกจะดี แต่เราจะมุ่งเน้นที่ Cache Storage API เนื่องจากมีการผสานรวมกับไลบรารี Service Worker ยอดนิยมอย่าง Workbox
แคชวิดีโอจาก Service Worker
เนื่องจากการดาวน์โหลดและแคชชิ้นงานขนาดใหญ่ เช่น วิดีโอ อาจเป็นงานที่ใช้เวลานานและใช้โปรเซสเซอร์มาก คุณจึงควรดำเนินการในเบื้องหลังนอกเทรดหลัก Service Worker มีประโยชน์อย่างยิ่งในการส่งต่อภารกิจการแคช โดยจะทำหน้าที่เป็นพร็อกซีระหว่างหน้าเว็บกับเครือข่าย ซึ่งช่วยให้ดักจับคำขอและใช้ตรรกะเพิ่มเติมกับการตอบกลับของเครือข่ายได้ เช่น กลยุทธ์การแคช
กลยุทธ์การแคชมีอยู่หลายแบบ และแต่ละแบบก็ออกแบบมาเพื่อช่วยในกรณีการใช้งานที่แตกต่างกัน เช่น หากต้องการแสดงไฟล์จากแคชหากมี หรือกลับไปใช้เครือข่ายหากไม่มี คุณสามารถเขียนโค้ดต่อไปนี้
self.addEventListener('fetch', function (event) { event.respondWith( caches.match(event.request).then(function (response) { return response || fetch(event.request); }), ); });
การจัดการนี้สำหรับประเภทชิ้นงานหรือ URL ต่างๆ ที่ต้องใช้กลยุทธ์การแคชที่แตกต่างกันอาจเป็นกระบวนการที่ซ้ำซากและมีโอกาสเกิดข้อผิดพลาดได้ Workbox มีชุดเครื่องมือต่างๆ รวมถึงตัวช่วยในการกำหนดเส้นทางและกลยุทธ์การแคช ซึ่งช่วยให้คุณเขียนโค้ด Service Worker ในลักษณะที่ประกาศได้มากขึ้นและนำกลับมาใช้ใหม่ได้
กลยุทธ์ก่อนหน้านี้เรียกว่า Cache First หากต้องการเขียนสิ่งเดียวกันโดยใช้ Workbox คุณจะต้องรวมสิ่งต่อไปนี้
registerRoute( ({ request }) => request.destination === 'video', new CacheFirst() );
Workbox มีสูตรที่คล้ายกันสำหรับกลยุทธ์การแคชอื่นๆ และงาน Service Worker ทั่วไป รวมถึงการผสานรวมกับเครื่องมือบิลด์ เช่น Webpack และ Rollup
เมื่อตั้งค่า Workbox แล้ว คุณจะต้องเลือกเวลาที่จะแคชวิดีโอ โดยมี 2 วิธีคือ โหลดทันทีเมื่อโหลดหน้าเว็บ หรือโหลดเมื่อมีการขอวิดีโอ
แนวทางที่ตั้งใจ
การแคชล่วงหน้าเป็นเทคนิคที่ใช้บันทึกไฟล์ลงในแคชระหว่างการติดตั้ง Service Worker เพื่อให้พร้อมใช้งานทันทีที่ Service Worker ทำงาน Workbox สามารถตั้งค่าการแคชล่วงหน้าสำหรับไฟล์ที่เข้าถึงได้โดยอัตโนมัติในระหว่างกระบวนการบิลด์
คุณใช้โค้ด Workbox ต่อไปนี้ใน Service Worker เพื่อแคชไฟล์ล่วงหน้าได้
import { addPlugins, precacheAndRoute } from 'workbox-precaching'; import { RangeRequestsPlugin } from 'workbox-range-requests'; addPlugins([new RangeRequestsPlugin()]); precacheAndRoute(self.__WB_MANIFEST);
import(s) - โหลดการเชื่อมโยงที่จำเป็นจากโมดูล Workbox ที่เกี่ยวข้อง เนื่องจาก Service Worker ยังไม่รองรับ ESModules ในทุกที่ คุณจึงต้องส่ง Service Worker ที่ขับเคลื่อนด้วย Workbox ผ่าน Bundler เพื่อให้ทำงานในการใช้งานจริงได้RangeRequestsPlugin- ช่วยให้คำขอที่มีส่วนหัวRangeได้รับการตอบสนองโดยการตอบกลับที่แคชไว้ ซึ่งจำเป็นเนื่องจากโดยปกติแล้วเบราว์เซอร์จะใช้ส่วนหัวRangeสำหรับเนื้อหาสื่อaddPlugins- ช่วยให้คุณเพิ่มปลั๊กอิน Workbox ลงในคำขอ Workbox ทุกรายการได้precacheAndRoute- เพิ่มรายการลงในรายการแคชล่วงหน้าและสร้างเส้นทางเพื่อจัดการคำขอเรียกข้อมูลที่เกี่ยวข้อง__WB_MANIFEST- ตัวยึดตำแหน่งที่ Workbox CLI (หรือปลั๊กอินเครื่องมือบิลด์) แทนที่ด้วยไฟล์ Manifest ของการแคชล่วงหน้า
ส่ง Service Worker ไปยัง Workbox CLI หรือเครื่องมือบิลด์ที่คุณเลือก แล้วกำหนดค่าวิธีสร้างแคชล่วงหน้า workbox-config.js ไฟล์ เช่น ไฟล์ต่อไปนี้ จะบอก CLI ว่าควรแสดงผล Service Worker อย่างไร
module.exports = { globDirectory: '.', globPatterns: ['**/*.{html,mp4}'], maximumFileSizeToCacheInBytes: 5000000, swSrc: 'sw.js', swDest: 'sw.js', };
globDirectory- โฟลเดอร์รูทที่จะเริ่มค้นหาไฟล์ที่แคชล่วงหน้าglobPatterns- รูปแบบไฟล์ ("glob") ที่ควรแคชล่วงหน้าmaximumFileSizeToCacheInBytes- ขีดจำกัดสูงสุดของขนาดไฟล์ที่แคชล่วงหน้าได้ในหน่วยไบต์swSrc- ตำแหน่งของไฟล์ที่จะใช้สร้าง Service WorkerswDest- ปลายทางของ Service Worker ที่สร้างขึ้น (อาจเป็นปลายทางเดียวกับไฟล์ต้นฉบับ แต่ตรวจสอบว่ามีself.__WB_MANIFESTสำหรับการเรียกใช้แต่ละครั้ง)
เมื่อกระบวนการบิลด์ทำงาน ระบบจะสร้าง Service Worker เวอร์ชันใหม่ และแทนที่ self.__WB_MANIFEST ด้วยรายการไฟล์ ซึ่งแต่ละไฟล์จะมีแฮชเพื่อระบุการแก้ไข
precacheAndRoute([ { revision: '524ac4b453c83f76eb9caeec11854ca5', url: 'ny.mp4', }, ]);
ทุกครั้งที่กระบวนการบิลด์ทำงาน ระบบจะเขียนรายการนี้ใหม่ด้วยชุดไฟล์ที่ตรงกันในปัจจุบันและแฮชการแก้ไขปัจจุบัน ซึ่งจะช่วยให้มั่นใจได้ว่าเมื่อใดก็ตามที่มีการเพิ่ม นำออก หรือเปลี่ยนแปลงไฟล์ Service Worker จะอัปเดตแคชในการติดตั้งครั้งถัดไป
วิธีแบบขี้เกียจ
หากไม่มีวิดีโอทั้งหมดในเวลาที่สร้าง หรือต้องการแคชวิดีโอเฉพาะเมื่อจำเป็น คุณควรใช้แนวทางแบบเลซี่ แนวทางนี้กำหนดให้ต้องแยกการแคชและการแสดงผล เนื่องจากระบบจะดึงเนื้อหาบางส่วนจากเครือข่ายในระหว่างการเล่นวิดีโอเท่านั้น การแคชไฟล์ขณะสตรีมจึงใช้ไม่ได้
แคชไฟล์
คุณสร้างแคชได้โดยใช้ Cache.open() จากนั้นเพิ่มไฟล์ลงในแคชได้โดยใช้ Cache.add() หรือ Cache.addAll() หากแอปได้รับรายการวิดีโอ JSON ที่จะแคช คุณจะเพิ่มวิดีโอเหล่านั้นลงในแคชวิดีโอได้ดังนี้
// Open video cache const cache = await caches.open('video-cache'); // Fetch list of videos const videos = await (await fetch('/video-list.json')).json(); // Add videos to cache await cache.addAll(videos);
ข้อดีของแนวทางนี้คือคุณสามารถควบคุมขั้นตอนการแคชแยกจากวงจรของ Service Worker ได้ แม้จะมาจาก Web Worker อื่นๆ ก็ตาม ข้อเสียคือส่วนการจัดการพื้นที่เก็บข้อมูลขึ้นอยู่กับนักพัฒนาแอป คุณต้องเขียนอัลกอริทึมของคุณเองเพื่อติดตามการเปลี่ยนแปลงไฟล์ ติดตามไฟล์ที่แคชอยู่ในเบราว์เซอร์ และจัดการการอัปเดตไฟล์เพื่อให้มั่นใจว่าเฉพาะไฟล์ที่เปลี่ยนแปลงเท่านั้นที่จะได้รับการอัปเดต
การแสดงไฟล์วิดีโอที่แคชไว้
จากนั้นจะใช้กลยุทธ์การแคชรันไทม์ของ Service Worker เช่น แคชก่อน เพื่อแสดงไฟล์วิดีโอที่แคชไว้ก่อนหน้านี้ได้
import { registerRoute } from 'workbox-routing'; import { CacheFirst } from 'workbox-strategies'; import { CacheableResponsePlugin } from 'workbox-cacheable-response'; import { RangeRequestsPlugin } from 'workbox-range-requests'; registerRoute( ({ request }) => request.destination === 'video', new CacheFirst({ cacheName: 'video-cache', plugins: [ new CacheableResponsePlugin({ statuses: [200], }), new RangeRequestsPlugin(), ], }), );
import(s) - โหลดการเชื่อมโยงที่จำเป็นจากโมดูล Workbox ที่เกี่ยวข้องregisterRoute-กำหนดเส้นทางคำขอไปยังฟังก์ชัน (กลยุทธ์การแคชและปลั๊กอิน) ที่ให้การตอบกลับCacheFirst- กลยุทธ์การแคชที่ตอบสนองคำขอจากแคช หากมี ไม่เช่นนั้นจะดึงข้อมูลจากเครือข่ายและอัปเดตแคชCacheableResponsePlugin- ใช้เพื่อระบุว่าต้องมีส่วนหัวใดบ้างเพื่อให้การตอบกลับแคชได้ ตรวจสอบว่ามีสถานะ 200 สำหรับวิดีโอแคชเส้นทางเท่านั้น เพื่อหลีกเลี่ยงการแคชการตอบกลับเนื้อหาบางส่วน (206) ขณะสตรีมวิดีโอRangeRequestsPlugin- ปลั๊กอินที่ช่วยให้คำขอที่มีส่วนหัวRangeได้รับการตอบสนองจากคำตอบที่แคชไว้ ซึ่งจำเป็นเนื่องจากโดยปกติแล้วเบราว์เซอร์จะใช้ส่วนหัวRangeสำหรับเนื้อหาสื่อ
การเพิ่มประสิทธิภาพการโหลดวิดีโอเป็นงานที่สำคัญสำหรับแอปที่สตรีมอย่างหนัก การใช้ประโยชน์จาก Cache Storage API และ Workbox ของเบราว์เซอร์จะช่วยให้คุณจัดการงานที่ยากนี้ได้ ซึ่งจะช่วยประหยัดแบนด์วิดท์ของผู้ใช้ ลดภาระของเซิร์ฟเวอร์ เล่นวิดีโอได้เร็วขึ้น และให้วิดีโอทำงานได้แม้ในขณะออฟไลน์