การจัดการการอัปเดตโปรแกรมทำงานของบริการแบบฉับพลัน

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

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

โค้ดที่จะใส่ในหน้าเว็บของคุณ

โค้ดต่อไปนี้จะทำงานในองค์ประกอบ <script> ในบรรทัดโดยใช้โมดูล JavaScript ที่นำเข้าจาก workbox-window เวอร์ชันที่โฮสต์ใน CDN โปรแกรมนี้จะลงทะเบียน Service Worker โดยใช้ workbox-window และจะตอบสนองหากโปรแกรมทำงานค้างในช่วงรอ เมื่อพบ Service Worker แล้ว โค้ดนี้จะแจ้งให้ผู้ใช้ทราบว่าเว็บไซต์มีเวอร์ชันที่อัปเดตแล้วให้ใช้งาน และแจ้งให้ผู้ใช้โหลดซ้ำ

<!-- This script tag uses JavaScript modules, so the proper `type` attribute value is required -->
<script type="module">
  // This code sample uses features introduced in Workbox v6.
  import {Workbox} from 'https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-window.prod.mjs';

  if ('serviceWorker' in navigator) {
    const wb = new Workbox('/sw.js');
    let registration;

    const showSkipWaitingPrompt = async (event) => {
      // Assuming the user accepted the update, set up a listener
      // that will reload the page as soon as the previously waiting
      // service worker has taken control.
      wb.addEventListener('controlling', () => {
        // At this point, reloading will ensure that the current
        // tab is loaded under the control of the new service worker.
        // Depending on your web app, you may want to auto-save or
        // persist transient state before triggering the reload.
        window.location.reload();
      });

      // When `event.wasWaitingBeforeRegister` is true, a previously
      // updated service worker is still waiting.
      // You may want to customize the UI prompt accordingly.

      // This code assumes your app has a promptForUpdate() method,
      // which returns true if the user wants to update.
      // Implementing this is app-specific; some examples are:
      // https://open-ui.org/components/alert.research or
      // https://open-ui.org/components/toast.research
      const updateAccepted = await promptForUpdate();

      if (updateAccepted) {
        wb.messageSkipWaiting();
      }
    };

    // Add an event listener to detect when the registered
    // service worker has installed but is waiting to activate.
    wb.addEventListener('waiting', (event) => {
      showSkipWaitingPrompt(event);
    });

    wb.register();
  }
</script>

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

โค้ดที่จะใส่ใน Service Worker

เมื่อได้รับโค้ดจากส่วนก่อนหน้าในหน้าเว็บแล้ว คุณจะต้องเพิ่มโค้ดบางอย่างลงใน Service Worker เพื่อให้โปรแกรมทราบว่าจะต้องข้ามช่วงรอเมื่อใด หากคุณใช้ generateSW จาก workbox-build และได้ตั้งค่าตัวเลือก skipWaiting เป็น false (ค่าเริ่มต้น) แล้ว คุณก็พร้อมที่จะใช้งาน เนื่องจากโค้ดด้านล่างจะรวมอยู่ในไฟล์ Service Worker ที่คุณสร้างขึ้นโดยอัตโนมัติ

หากคุณกำลังเขียนโปรแกรมทำงานของบริการของคุณเอง โดยอาจใช้ร่วมกับเครื่องมือสร้างบิวด์ของ Workbox ในโหมด injectManifest คุณจะต้องเพิ่มโค้ดต่อไปนี้ด้วยตนเอง

addEventListener('message', (event) => {
  if (event.data && event.data.type === 'SKIP_WAITING') {
    self.skipWaiting();
  }
});

การดำเนินการนี้จะรอฟังข้อความที่ส่งถึง Service Worker จาก workbox-window ที่มีค่า type เป็น SKIP_WAITING และเมื่อเกิดเหตุการณ์นี้ ให้เรียก self.skipWaiting() เมธอด messageSkipWaiting() ใน workbox-window ที่แสดงในตัวอย่างโค้ดก่อนหน้านี้มีหน้าที่ส่งข้อความนี้

คุณต้องการแสดงข้อความแจ้งหรือไม่

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

  • คุณใช้การแคชล่วงหน้าอย่างเข้มงวด หากกังวลเกี่ยวกับเนื้อหาแบบคงที่ คุณอาจมีปัญหาในภายหลังในกรณีที่ใช้กลยุทธ์ที่เน้นเครือข่ายเป็นหลักหรือเฉพาะเครือข่ายเท่านั้นสำหรับคำขอการนำทาง แต่ใช้เนื้อหาแบบคงที่ที่โหลดแบบ Lazy Loading ซึ่งอาจทำให้เกิดสถานการณ์ต่างๆ ที่เนื้อหาซึ่งมีเวอร์ชันอาจมีการเปลี่ยนแปลง และ Service Worker ไม่ได้แคชเนื้อหาเหล่านั้นไว้ล่วงหน้า การเสนอปุ่มโหลดซ้ำที่นี่อาจหลีกเลี่ยงลักษณะการทำงานที่ไม่คาดคิดได้
  • หากแสดง HTML ที่เก็บไว้ล่วงหน้า ในกรณีนี้ คุณควรอย่างเสนอปุ่มโหลดซ้ำในการอัปเดต Service Worker เนื่องจากการอัปเดต HTML นั้นจะไม่ได้รับการยอมรับจนกว่า Service Worker ที่อัปเดตจะเข้าควบคุม
  • หากคุณไม่ได้อาศัยการแคชรันไทม์เป็นส่วนใหญ่ เมื่อแคชทรัพยากรขณะรันไทม์ คุณไม่จำเป็นต้องแจ้งให้ผู้ใช้ทราบว่าควรโหลดซ้ำ เมื่อมีการเปลี่ยนแปลงเนื้อหาที่มีเวอร์ชัน ระบบจะเพิ่มเนื้อหาดังกล่าวลงในแคชรันไทม์ในหลักสูตรที่ครบกำหนด ในกรณีที่คำขอการนำทางใช้กลยุทธ์แบบเครือข่ายเป็นหลักหรือเฉพาะเครือข่ายเท่านั้น
  • เมื่อใช้กลยุทธ์ไม่อัปเดตขณะตรวจสอบใหม่ คุณอาจพิจารณาใช้โมดูล workbox-broadcast-update เพื่อแจ้งให้ผู้ใช้ทราบเกี่ยวกับการอัปเดตของโปรแกรมทำงานของบริการ

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