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

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

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

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

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

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

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

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

หากคุณเขียน 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 ที่แคชล่วงหน้า ในกรณีนี้ คุณควรพิจารณานำเสนอปุ่มโหลดซ้ำในการอัปเดตโปรแกรมทำงานของบริการเป็นอย่างยิ่ง เนื่องจากระบบจะจำการอัปเดต HTML นั้นไม่ได้จนกว่าโปรแกรมทำงานของบริการที่อัปเดตจะควบคุมการอัปเดต
  • หากคุณไม่ได้ใช้การแคชรันไทม์เป็นส่วนใหญ่ เมื่อแคชทรัพยากรระหว่างรันไทม์ คุณไม่จำเป็นต้องแจ้งให้ผู้ใช้ทราบว่าควรโหลดซ้ำ เมื่อเนื้อหาที่มีเวอร์ชันมีการเปลี่ยนแปลง ระบบจะเพิ่มเนื้อหาเหล่านั้นลงในแคชรันไทม์ในวันที่ครบกำหนด โดยสมมติว่าคำขอการนำทางใช้กลยุทธ์แบบเครือข่ายเป็นอันดับแรกหรือเฉพาะเครือข่ายเท่านั้น
  • เมื่อใช้กลยุทธ์ไม่มีอัปเดตขณะตรวจสอบความถูกต้องอีกครั้ง คุณอาจพิจารณาใช้โมดูล workbox-broadcast-update เพื่อแจ้งให้ผู้ใช้ทราบเกี่ยวกับการอัปเดตโปรแกรมทำงานของบริการ

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