การจัดการพื้นที่เก็บข้อมูลวิดีโอบนเว็บ

วิดีโอเป็นชิ้นงานที่จัดการได้ยาก การสตรีมต้องใช้แบนด์วิดท์จำนวนมาก และการแคชก็ไม่ใช่เรื่องง่าย ปัญหาเหล่านี้จะยิ่งรุนแรงขึ้นเมื่อวิดีโอเล่นซ้ำ เช่น ในจอแสดงผลคีออส ตัวอย่างเช่น หากบริษัทมีอุปกรณ์หลายร้อยเครื่องที่เล่นวิดีโอ 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 Worker
  • swDest - ปลายทางของ 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 ของเบราว์เซอร์จะช่วยให้คุณจัดการงานที่ยากนี้ได้ ซึ่งจะช่วยประหยัดแบนด์วิดท์ของผู้ใช้ ลดภาระของเซิร์ฟเวอร์ เล่นวิดีโอได้เร็วขึ้น และให้วิดีโอทำงานได้แม้ในขณะออฟไลน์