เผยแพร่การอัปเดตไปยังหน้าเว็บที่มี Service Worker

Andrew Guan
Andrew Guan

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

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

เราจะเรียกกรณีการใช้งานประเภทนี้ที่โปรแกรมทำงานของบริการไม่จำเป็นต้องรับข้อความจาก หน้าเว็บเพื่อเริ่มการสื่อสาร "ประกาศการอัปเดต" ในคู่มือนี้เราจะอธิบายถึง ในการใช้งานการสื่อสารประเภทนี้ระหว่างหน้าเว็บและโปรแกรมทำงานของบริการ โดยใช้มาตรฐาน API ของเบราว์เซอร์และไลบรารี Workbox

เคสการผลิต

Tinder

PWA ของ Tinder ใช้ workbox-window เพื่อฟัง ช่วงเวลาสำคัญในวงจรของ Service Worker จากหน้าเว็บ ("ติดตั้งแล้ว" "ควบคุมแล้ว" และ "เปิดใช้งานแล้ว") วิธีนี้จะแสดง "มีอัปเดต" ปรากฏขึ้นเมื่อมีโปรแกรมทำงานของบริการใหม่เข้ามาทำงาน เพื่อให้รีเฟรช PWA และเข้าถึงฟีเจอร์ล่าสุดได้

วันที่ ภาพหน้าจอของเว็บแอป "มีอัปเดต" ของ Tinder
ใน PWA ของ Tinder โปรแกรมทำงานของบริการจะแจ้งหน้าเว็บว่าเวอร์ชันใหม่พร้อมใช้งานแล้ว และหน้าเว็บจะแสดงให้ผู้ใช้เห็นว่า "มีการอัปเดต" แบนเนอร์

สควอช

ใน Squoosh PWA เมื่อ Service Worker แคชข้อมูลที่จำเป็นทั้งหมด เนื้อหาเพื่อทำให้ทำงานแบบออฟไลน์ได้ จะมีการส่งข้อความไปยังหน้าเว็บเพื่อแสดงว่า "พร้อมทำงานแบบออฟไลน์" ข้อความโทสต์ แจ้งให้ผู้ใช้ทราบเกี่ยวกับฟีเจอร์:

วันที่ ภาพหน้าจอของเว็บแอป Squoosh "พร้อมทำงานแบบออฟไลน์"
ใน PWA ของ Squoosh นั้น Service Worker จะแจ้งการอัปเดตไปยังหน้าเมื่อแคชพร้อมใช้งาน และหน้าเว็บจะแสดงข้อความ "พร้อมทำงานแบบออฟไลน์" ข้อความโทสต์

การใช้ Workbox

ฟังเหตุการณ์ในวงจรของโปรแกรมทำงานของบริการ

workbox-window มีอินเทอร์เฟซที่ตรงไปตรงมาซึ่งฟังวงจรชีวิตที่สำคัญของโปรแกรมทำงานของบริการ กิจกรรม ในการทำงานเบื้องหลัง ไลบรารีจะใช้ API ฝั่งไคลเอ็นต์ เช่น updatefound และ statechange และระบุ Listener เหตุการณ์ในระดับที่สูงกว่าในออบเจ็กต์ workbox-window ซึ่งทำให้ ผู้ใช้ที่จะใช้เหตุการณ์เหล่านี้

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

const wb = new Workbox('/sw.js');

wb.addEventListener('installed', (event) => {
  if (event.isUpdate) {
    // Show "Update App" banner
  }
});

wb.register();

แจ้งหน้าการเปลี่ยนแปลงข้อมูลแคช

แพ็กเกจ Workbox workbox-broadcast-update เป็นวิธีมาตรฐานในการแจ้งไคลเอ็นต์หน้าต่างว่าการตอบกลับที่แคชไว้ได้รับการอัปเดตแล้ว นี่คือ ใช้บ่อยที่สุดร่วมกับฟังก์ชัน StalewhenReValidate กลยุทธ์

ในการเผยแพร่การอัปเดต ให้เพิ่ม broadcastUpdate.BroadcastUpdatePlugin ลงในตัวเลือกกลยุทธ์ใน ฝั่งของ Service Worker

import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
import {BroadcastUpdatePlugin} from 'workbox-broadcast-update';

registerRoute(
  ({url}) => url.pathname.startsWith('/api/'),
  new StaleWhileRevalidate({
    plugins: [
      new BroadcastUpdatePlugin(),
    ],
  })
);

ในเว็บแอป คุณจะฟังเหตุการณ์ต่อไปนี้ได้

navigator.serviceWorker.addEventListener('message', async (event) => {
  // Optional: ensure the message came from workbox-broadcast-update
  if (event.data.meta === 'workbox-broadcast-update') {
    const {cacheName, updatedUrl} = event.data.payload;

    // Do something with cacheName and updatedUrl.
    // For example, get the cached content and update
    // the content on the page.
    const cache = await caches.open(cacheName);
    const updatedResponse = await cache.match(updatedUrl);
    const updatedText = await updatedResponse.text();
  }
});

การใช้ API ของเบราว์เซอร์

หากฟังก์ชันที่ Workbox มีให้ไม่เพียงพอต่อความต้องการของคุณ โปรดใช้เบราว์เซอร์ต่อไปนี้ API สำหรับใช้ "การอัปเดตการออกอากาศ":

API ช่องสำหรับการออกอากาศ

โปรแกรมทำงานของบริการสร้าง BroadcastChannel ของออบเจ็กต์ และเริ่มส่ง ข้อความไปที่ข้อความนี้ บริบทใดๆ (เช่น หน้าเว็บ) ที่สนใจรับข้อความเหล่านี้สามารถสร้างอินสแตนซ์ BroadcastChannel และใช้เครื่องจัดการข้อความเพื่อรับข้อความ

หากต้องการแจ้งหน้าเว็บเมื่อมีการติดตั้ง Service Worker ใหม่ ให้ใช้โค้ดต่อไปนี้

// Create Broadcast Channel to send messages to the page
const broadcast = new BroadcastChannel('sw-update-channel');

self.addEventListener('install', function (event) {
  // Inform the page every time a new service worker is installed
  broadcast.postMessage({type: 'CRITICAL_SW_UPDATE'});
});

หน้าเว็บจะฟังเหตุการณ์เหล่านี้โดยสมัครรับข้อมูลของ sw-update-channel:

// Create Broadcast Channel and listen to messages sent to it
const broadcast = new BroadcastChannel('sw-update-channel');

broadcast.onmessage = (event) => {
  if (event.data && event.data.type === 'CRITICAL_SW_UPDATE') {
    // Show "update to refresh" banner to the user.
  }
};

นี่เป็นเทคนิคง่ายๆ แต่ข้อจำกัดที่มีคือการรองรับเบราว์เซอร์: ขณะที่เขียนบทความนี้ Safari ไม่รองรับ API นี้

API ของไคลเอ็นต์

API ไคลเอ็นต์มีเคล็ดลับ วิธีสื่อสารกับไคลเอ็นต์หลายๆ รายจาก Service Worker โดยทำซ้ำอาร์เรย์ ออบเจ็กต์ Client

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

// Obtain an array of Window client objects
self.clients.matchAll(options).then(function (clients) {
  if (clients && clients.length) {
    // Respond to last focused tab
    clients[0].postMessage({type: 'MSG_ID'});
  }
});

หน้านี้จะมีตัวแฮนเดิลข้อความเพื่อสกัดกั้นข้อความเหล่านี้

// Listen to messages
navigator.serviceWorker.onmessage = (event) => {
     if (event.data && event.data.type === 'MSG_ID') {
         // Process response
   }
};

API ไคลเอ็นต์เป็นตัวเลือกที่ยอดเยี่ยมสำหรับกรณีต่างๆ เช่น การเผยแพร่ข้อมูลไปยังแท็บที่ใช้งานอยู่หลายแท็บ API ได้รับการสนับสนุนจากเบราว์เซอร์หลักทั้งหมด แต่ไม่ใช่ทุกเมธอดของ API ตรวจสอบการรองรับเบราว์เซอร์ก่อน อยู่แล้ว

ช่องทางของข้อความ

ต้องมีช่องทางข้อความ ขั้นตอนการกำหนดค่าเริ่มต้นโดยการส่งพอร์ตจากหน้าเว็บไปยังโปรแกรมทำงานของบริการเพื่อสร้าง ระหว่าง 2 ช่องทางนี้ หน้านี้จะสร้างอินสแตนซ์ของออบเจ็กต์ MessageChannel และส่งผ่าน พอร์ตไปยัง Service Worker ผ่านอินเทอร์เฟซ postMessage():

const messageChannel = new MessageChannel();

// Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
  messageChannel.port2,
]);

หน้าเว็บจะรอฟังข้อความโดยใช้ "onmessage" บนพอร์ตนั้น

// Listen to messages
messageChannel.port1.onmessage = (event) => {
  // Process message
};

Service Worker ได้รับพอร์ตและบันทึกการอ้างอิงไปยังพอร์ตนี้:

// Initialize
let communicationPort;

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PORT_INITIALIZATION') {
    communicationPort = event.ports[0];
  }
});

จากจุดนี้ อุปกรณ์จะส่งข้อความไปยังหน้าเว็บได้โดยเรียกใช้ postMessage() ในการอ้างอิงไปยัง พอร์ต:

// Communicate
communicationPort.postMessage({type: 'MSG_ID' });

MessageChannel อาจใช้งานยากเนื่องจากต้องเริ่มต้นพอร์ต แต่ สนับสนุนโดยเบราว์เซอร์หลักทั้งหมด

ขั้นตอนถัดไป

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

สำหรับรูปแบบเพิ่มเติมของการสื่อสารของ Windows และ Service Worker โปรดดูที่

  • คู่มือการแคชที่สำคัญ: การเรียกใช้ Service Worker จากหน้าเว็บเพื่อ แคชทรัพยากรล่วงหน้า (เช่น ในสถานการณ์การดึงข้อมูลล่วงหน้า)
  • การสื่อสารแบบ 2 ทาง: การมอบสิทธิ์งานให้กับ Service Worker (เช่น มีการดาวน์โหลดข้อมูลจำนวนมาก) และคอยอัปเดตหน้าเว็บเกี่ยวกับความคืบหน้า

แหล่งข้อมูลเพิ่มเติม