แพ็กเกจ workbox-window
คือชุดโมดูลที่มีจุดประสงค์ให้ทำงานในบริบท window
ซึ่งก็คือภายในหน้าเว็บของคุณ และเป็นส่วนเสริมของแพ็กเกจงานอื่นๆ
ที่ทำงานในโปรแกรมทำงานของบริการ
ฟีเจอร์/เป้าหมายที่สำคัญของ workbox-window
ได้แก่
- เพื่อลดความซับซ้อนของการลงทะเบียนและอัปเดตโปรแกรมทำงานของบริการโดยช่วยให้นักพัฒนาซอฟต์แวร์ระบุช่วงเวลาที่สำคัญที่สุดในวงจรการทำงานของโปรแกรมทำงาน รวมถึงทำให้ตอบสนองต่อช่วงเวลาเหล่านั้นได้ง่ายขึ้น
- เพื่อป้องกันไม่ให้นักพัฒนาซอฟต์แวร์ทำข้อผิดพลาดที่พบบ่อยที่สุด
- หากต้องการเปิดใช้การสื่อสารที่ง่ายขึ้นระหว่างโค้ดที่ทำงานอยู่ใน Service Worker กับโค้ดที่ทำงานในหน้าต่าง
การนำเข้าและการใช้หน้าต่างกล่องงาน
จุดแรกเข้าหลักสำหรับแพ็กเกจ workbox-window
คือคลาส Workbox
ซึ่งคุณจะนำเข้ามาในโค้ดได้จาก CDN ของเราหรือใช้เครื่องมือรวมกลุ่ม JavaScript ยอดนิยมก็ได้
การใช้ CDN ของเรา
วิธีที่ง่ายที่สุดในการนำเข้าคลาส Workbox
ในเว็บไซต์คือจาก CDN ของเรา ดังนี้
<script type="module">
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');
wb.register();
}
</script>
โปรดทราบว่าตัวอย่างนี้ใช้ <script type="module">
และคำสั่ง import
เพื่อโหลดคลาส Workbox
แม้คุณอาจคิดว่าจำเป็นต้องแปลงโค้ดนี้เพื่อให้ทำงานได้ในเบราว์เซอร์รุ่นเก่ากว่านั้น จริงๆ แล้วไม่จำเป็น
เบราว์เซอร์หลักทั้งหมดที่รองรับ Service Worker จะรองรับโมดูล JavaScript แบบเนทีฟด้วย ดังนั้นจึงเหมาะที่สุดที่จะแสดงโค้ดนี้ในทุกเบราว์เซอร์ (เบราว์เซอร์รุ่นเก่าจะไม่สนใจ)
กำลังโหลด Workbox ด้วย Bundler ของ JavaScript
แม้ว่าไม่จำเป็นต้องใช้เครื่องมือใดๆ ในการใช้ workbox-window
แต่หากโครงสร้างพื้นฐานการพัฒนาของคุณมี Bundler เช่น Webpack หรือ Rollup ที่ทำงานกับทรัพยากร Dependency npm อยู่แล้ว คุณก็ใช้ทรัพยากรดังกล่าวเพื่อโหลด workbox-window
ได้
ขั้นตอนแรกคือ
ติดตั้ง
workbox-window
เป็นทรัพยากร Dependency ของแอปพลิเคชัน ดังนี้
npm install workbox-window
จากนั้นในไฟล์ JavaScript ของแอปพลิเคชันไฟล์ใดไฟล์หนึ่ง ให้ไปที่ import
Workbox โดยระบุชื่อแพ็กเกจ workbox-window
ดังนี้
import {Workbox} from 'workbox-window';
if ('serviceWorker' in navigator) {
const wb = new Workbox('/sw.js');
wb.register();
}
หาก Bundler รองรับการแยกโค้ดผ่านคำสั่งการนำเข้าแบบไดนามิก คุณจะโหลด workbox-window
อย่างมีเงื่อนไขได้ด้วย ซึ่งจะช่วยลดขนาดของ Bundle หลักของหน้าได้
แม้ว่า workbox-window
จะมีขนาดค่อนข้างเล็ก แต่ก็ไม่มีเหตุผลที่จะต้องโหลดตรรกะของแอปพลิเคชันหลักของเว็บไซต์ไว้ เนื่องจากการทำงานของ Service Worker จึงเป็นการเพิ่มประสิทธิภาพแบบต่อเนื่อง
if ('serviceWorker' in navigator) {
const {Workbox} = await import('workbox-window');
const wb = new Workbox('/sw.js');
wb.register();
}
แนวคิดการรวมกลุ่มขั้นสูง
ไฟล์บิลด์ที่อ้างอิงโดยช่อง main
และ module
ของ workbox-window
ใน package.json
จะแปลงเป็น ES5 ซึ่งแตกต่างจากแพ็กเกจ Workbox ที่เรียกใช้ใน Service Worker ซึ่งทำให้เครื่องมือเหล่านี้เข้ากันได้กับเครื่องมือสร้างในปัจจุบัน ซึ่งบางรายการไม่อนุญาตให้นักพัฒนาซอฟต์แวร์ถ่ายโอนทรัพยากร Dependency ของ node_module
ได้ทั้งหมด
หากระบบของบิลด์อนุญาตให้คุณสลับทรัพยากร Dependency (หรือคุณไม่จำเป็นต้องเปลี่ยนรูปแบบโค้ด) ก็ควรนำเข้าไฟล์ต้นฉบับเฉพาะแทนการนำเข้าตัวแพ็กเกจ
ต่อไปนี้คือวิธีต่างๆ ที่คุณจะนำเข้า Workbox
ได้ รวมถึงคำอธิบายว่าแต่ละรายการจะแสดงผลอะไร
// Imports a UMD version with ES5 syntax
// (pkg.main: "build/workbox-window.prod.umd.js")
const {Workbox} = require('workbox-window');
// Imports the module version with ES5 syntax
// (pkg.module: "build/workbox-window.prod.es5.mjs")
import {Workbox} from 'workbox-window';
// Imports the module source file with ES2015+ syntax
import {Workbox} from 'workbox-window/Workbox.mjs';
ตัวอย่าง
เมื่อนำเข้าคลาส Workbox
แล้ว คุณจะใช้คลาสดังกล่าวเพื่อลงทะเบียนและโต้ตอบกับ Service Worker ได้ ตัวอย่างวิธีที่คุณอาจใช้ Workbox
ในแอปพลิเคชันมีดังนี้
ลงทะเบียน Service Worker และแจ้งให้ผู้ใช้ทราบในครั้งแรกที่โปรแกรมทำงานของบริการทำงาน
โปรแกรมทำงานของบริการสำหรับผู้ใช้เว็บแอปพลิเคชันจำนวนมากต้องแคชเนื้อหาล่วงหน้าเพื่อให้แอปทำงานแบบออฟไลน์เมื่อโหลดหน้าเว็บในครั้งต่อๆ ไป ในบางกรณี การบอกให้ผู้ใช้ทราบว่า แอปพร้อมให้บริการแบบออฟไลน์แล้ว
const wb = new Workbox('/sw.js');
wb.addEventListener('activated', event => {
// `event.isUpdate` will be true if another version of the service
// worker was controlling the page when this version was registered.
if (!event.isUpdate) {
console.log('Service worker activated for the first time!');
// If your service worker is configured to precache assets, those
// assets should all be available now.
}
});
// Register the service worker after event listeners have been added.
wb.register();
แจ้งผู้ใช้หาก Service Worker ติดตั้งแล้วแต่ต้องรอเปิดใช้งาน
เมื่อหน้าเว็บที่ควบคุมโดย Service Worker ที่มีอยู่ลงทะเบียน Service Worker ใหม่โดยค่าเริ่มต้นนั้น Service Worker จะไม่เปิดใช้งานจนกว่าไคลเอ็นต์ทั้งหมดที่ควบคุมโดย Service Worker จะเริ่มต้นยกเลิกการโหลดโดยสมบูรณ์
ปัญหานี้มักทำให้นักพัฒนาซอฟต์แวร์สับสน โดยเฉพาะอย่างยิ่งในกรณีที่การโหลดหน้าเว็บปัจจุบันซ้ำไม่ทำให้โปรแกรมทำงานของบริการใหม่เปิดใช้งาน
คลาส Workbox
มีเหตุการณ์ waiting
ที่คุณรับฟังได้เพื่อช่วยลดความสับสนและอธิบายให้ชัดเจนว่าจะเกิดสถานการณ์เช่นนี้ขึ้นเมื่อใด
const wb = new Workbox('/sw.js');
wb.addEventListener('waiting', event => {
console.log(
`A new service worker has installed, but it can't activate` +
`until all tabs running the current version have fully unloaded.`
);
});
// Register the service worker after event listeners have been added.
wb.register();
แจ้งผู้ใช้เกี่ยวกับการอัปเดตแคชจากแพ็กเกจ workbox-broadcast-update
แพ็กเกจ workbox-broadcast-update
เป็นวิธีที่ยอดเยี่ยมในการแสดงเนื้อหาจากแคช (เพื่อให้นำส่งได้อย่างรวดเร็ว) ทั้งยังสามารถแจ้งให้ผู้ใช้ทราบการอัปเดตเนื้อหานั้น (โดยใช้กลยุทธ์ "ไม่มีอัปเดตขณะตรวจสอบใหม่)
หากต้องการรับการอัปเดตจากหน้าต่าง คุณจะฟังเหตุการณ์ message
ประเภท CACHE_UPDATED
ได้ดังนี้
const wb = new Workbox('/sw.js');
wb.addEventListener('message', event => {
if (event.data.type === 'CACHE_UPDATED') {
const {updatedURL} = event.data.payload;
console.log(`A newer version of ${updatedURL} is available!`);
}
});
// Register the service worker after event listeners have been added.
wb.register();
ส่งรายการ URL ให้โปรแกรมทำงานของบริการเพื่อแคช
สำหรับแอปพลิเคชันบางตัว อาจเป็นไปได้ที่จะทราบเนื้อหาทั้งหมดที่ต้องทำการแคชล่วงหน้าในเวลาสร้าง แต่บางแอปพลิเคชันจะแสดงหน้าเว็บที่แตกต่างกันโดยสิ้นเชิง ขึ้นอยู่กับ URL ที่ผู้ใช้ไปถึงเป็นอันดับแรก
สำหรับแอปในหมวดหมู่หลัง คุณอาจต้องแคชเฉพาะเนื้อหาที่จำเป็นสำหรับหน้าเว็บที่ผู้ใช้เข้าชมเท่านั้น เมื่อใช้แพ็กเกจ workbox-routing
คุณสามารถส่งรายการ URL ของเราเตอร์ไปยังแคชได้ และระบบจะแคช URL เหล่านั้นตามกฎที่กำหนดไว้บนเราเตอร์เอง
ตัวอย่างนี้จะส่งรายการ URL ที่โหลดโดยหน้าเว็บไปยังเราเตอร์ทุกครั้งที่มีการเปิดใช้งาน Service Worker ใหม่ โปรดทราบว่าคุณส่ง URL ทั้งหมดได้ เนื่องจากระบบจะแคชเฉพาะ URL ที่ตรงกับเส้นทางที่กำหนดไว้ใน Service Worker เท่านั้น
const wb = new Workbox('/sw.js');
wb.addEventListener('activated', event => {
// Get the current page URL + all resources the page loaded.
const urlsToCache = [
location.href,
...performance.getEntriesByType('resource').map(r => r.name),
];
// Send that list of URLs to your router in the service worker.
wb.messageSW({
type: 'CACHE_URLS',
payload: {urlsToCache},
});
});
// Register the service worker after event listeners have been added.
wb.register();
ช่วงเวลาในวงจรการทำงานของ Service Worker ที่สำคัญ
วงจรการทำงานของบริการนั้นซับซ้อนและอาจเป็นเรื่องท้าทายในการทำความเข้าใจอย่างถ่องแท้ เหตุผลหนึ่งที่มีความซับซ้อนก็คือต้องจัดการ Edge Case ทั้งหมดสำหรับการใช้งาน Service Worker ที่เป็นไปได้ทั้งหมด (เช่น การลงทะเบียน Service Worker มากกว่า 1 โปรแกรม ลงทะเบียน Service Worker ต่างๆ ในเฟรมต่างกัน ลงทะเบียน Service Worker ด้วยชื่อต่างกัน เป็นต้น)
แต่นักพัฒนาซอฟต์แวร์ส่วนใหญ่ที่ใช้ Service Worker ไม่ควรกังวลเกี่ยวกับ Edge Case เหล่านี้ทั้งหมดเพราะการใช้งานนั้นค่อนข้างง่าย นักพัฒนาซอฟต์แวร์ส่วนใหญ่จะลงทะเบียน Service Worker เพียง 1 ครั้งต่อการโหลดหน้าเว็บ และไม่เปลี่ยนชื่อไฟล์ Service Worker ที่ทำให้ใช้งานได้กับเซิร์ฟเวอร์
คลาส Workbox
จะนำมุมมองที่ง่ายกว่านี้เข้ามาสำหรับวงจรการทำงานของ Service Worker โดยแบ่งการลงทะเบียนโปรแกรมทำงานของบริการทั้งหมดออกเป็น 2 หมวดหมู่ ได้แก่ โปรแกรมทำงานของบริการเอง โปรแกรมทำงานของบริการที่ลงทะเบียนไว้ และโปรแกรมทำงานของบริการภายนอก ดังนี้
- Service Worker ที่ลงทะเบียนแล้ว: โปรแกรมทำงานของบริการที่เริ่มติดตั้งเนื่องจาก
Workbox
การเรียกใช้อินสแตนซ์register()
หรือโปรแกรมทำงานของบริการที่ใช้งานอยู่แล้ว หากการเรียกใช้register()
ไม่ทริกเกอร์เหตุการณ์updatefound
ในการลงทะเบียน - โปรแกรมทำงานของบริการภายนอก: โปรแกรมทำงานของบริการที่เริ่มติดตั้งโดยอิสระของการเรียกใช้อินสแตนซ์
Workbox
ที่เรียกใช้register()
ปัญหานี้มักเกิดขึ้นเมื่อผู้ใช้เปิดเว็บไซต์เวอร์ชันใหม่ในแท็บอื่น เมื่อเหตุการณ์มาจาก Service Worker ภายนอก ระบบจะตั้งค่าพร็อพเพอร์ตี้isExternal
ของเหตุการณ์เป็นtrue
เมื่อคำนึงถึง Service Worker ทั้ง 2 ประเภทนี้แล้ว ต่อไปนี้เป็นรายละเอียดช่วงเวลาสำคัญในวงจรการทำงานของโปรแกรมทำงานของบริการทั้งหมด รวมทั้งคำแนะนำจากนักพัฒนาซอฟต์แวร์เกี่ยวกับวิธีจัดการกับช่วงเวลาเหล่านั้น
ครั้งแรกที่มีการติดตั้ง Service Worker
คุณอาจต้องการดำเนินการกับการติดตั้งโปรแกรมทำงานของบริการครั้งแรกโดยแตกต่างจากการอัปเดตในอนาคตทั้งหมด
ใน workbox-window
คุณแยกความแตกต่างระหว่างการติดตั้งครั้งแรกกับการอัปเดตในอนาคตได้โดยตรวจสอบพร็อพเพอร์ตี้ isUpdate
ในเหตุการณ์ใดก็ได้ต่อไปนี้ สำหรับการติดตั้งครั้งแรก isUpdate
จะเป็น false
const wb = new Workbox('/sw.js');
wb.addEventListener('installed', event => {
if (!event.isUpdate) {
// First-installed code goes here...
}
});
wb.register();
เมื่อพบ Service Worker เวอร์ชันอัปเดต
เมื่อ Service Worker ใหม่เริ่มติดตั้ง แต่เวอร์ชันที่มีอยู่กำลังควบคุมหน้าเว็บอยู่ในขณะนี้ พร็อพเพอร์ตี้ isUpdate
ของเหตุการณ์ต่อไปนี้ทั้งหมดจะเป็น true
ปฏิกิริยาของคุณในสถานการณ์นี้มักจะแตกต่างจากการติดตั้งครั้งแรก เพราะคุณต้องจัดการเวลาและวิธีที่ผู้ใช้จะได้รับการอัปเดตนี้
เมื่อพบ Service Worker เวอร์ชันที่ไม่คาดคิด
บางครั้งผู้ใช้จะเปิดเว็บไซต์ของคุณไว้ในแท็บเบื้องหลังเป็นเวลานานมาก พวกเขาอาจเปิดแท็บใหม่และมาที่เว็บไซต์ของคุณโดยที่ไม่รู้ตัวว่าเว็บไซต์เปิดในแท็บเบื้องหลังอยู่แล้ว ในกรณีดังกล่าว เป็นไปได้ว่าคุณมีเว็บไซต์ 2 เวอร์ชันที่ทำงานพร้อมกัน และอาจทำให้เกิดปัญหาที่น่าสนใจสำหรับคุณในฐานะนักพัฒนาซอฟต์แวร์
ลองพิจารณาสถานการณ์ที่คุณมีแท็บ A ที่ทำงานอยู่ เวอร์ชัน 1 ของเว็บไซต์และแท็บ B ที่ทำงานอยู่ เวอร์ชัน 2 เมื่อแท็บ B โหลด เวอร์ชันของ Service Worker ที่มาพร้อมกับ v1 จะควบคุมแท็บนั้น แต่หน้าเว็บที่แสดงโดยเซิร์ฟเวอร์ (หากใช้กลยุทธ์การแคชเครือข่ายเป็นหลักสำหรับคำขอการนำทางของคุณ) จะมีชิ้นงาน v2 ทั้งหมดของคุณ
แต่โดยทั่วไปกรณีนี้จะไม่เป็นปัญหาสำหรับแท็บ B เนื่องจากเมื่อคุณเขียนโค้ด v2 คุณก็ทราบวิธีการทำงานของโค้ด v1 ของคุณ อย่างไรก็ตาม นี่อาจเป็นปัญหาสำหรับแท็บ A เนื่องจากโค้ด v1 ของคุณไม่สามารถคาดการณ์สิ่งที่อาจทำให้โค้ด v2 ของคุณเปลี่ยนแปลงไปได้
เพื่อช่วยรับมือกับสถานการณ์เหล่านี้ workbox-window
จะส่งเหตุการณ์ในวงจรเมื่อตรวจพบอัปเดตจาก Service Worker "ภายนอก" โดยที่ภายนอกหมายถึงเวอร์ชันใดก็ตามที่ไม่ใช่เวอร์ชันที่ลงทะเบียนอินสแตนซ์ Workbox
ปัจจุบัน
ใน Workbox เวอร์ชัน 6 ขึ้นไป เหตุการณ์เหล่านี้จะเทียบเท่ากับเหตุการณ์ที่บันทึกด้านบน โดยมีการตั้งค่าพร็อพเพอร์ตี้ isExternal: true
ในออบเจ็กต์เหตุการณ์แต่ละรายการ หากเว็บแอปพลิเคชันจำเป็นต้องใช้ตรรกะที่เฉพาะเจาะจงเพื่อจัดการกับ Service Worker "ภายนอก" คุณก็ตรวจสอบพร็อพเพอร์ตี้นั้นในเครื่องจัดการเหตุการณ์ได้
การหลีกเลี่ยงข้อผิดพลาดที่พบบ่อย
หนึ่งในฟีเจอร์ที่มีประโยชน์มากที่สุดที่ Workbox มีให้คือการบันทึกของนักพัฒนาซอฟต์แวร์ โดยเฉพาะอย่างยิ่งสำหรับ workbox-window
เราทราบดีว่าการพัฒนาด้วย Service Worker มักเป็นเรื่องที่สับสน และเมื่อเจอสิ่งที่ขัดกับสิ่งที่คุณคาดหวัง คุณก็อาจหาสาเหตุได้ยาก
เช่น เมื่อทำการเปลี่ยนแปลง Service Worker และโหลดหน้าเว็บซ้ำ คุณอาจไม่เห็นการเปลี่ยนแปลงนั้นในเบราว์เซอร์ สาเหตุที่เป็นไปได้มากที่สุดสำหรับปัญหานี้คือ โปรแกรมทำงานของบริการยังรอเปิดใช้งานอยู่
แต่เมื่อลงทะเบียน Service Worker ด้วยคลาส Workbox
คุณจะได้รับการแจ้งเตือนเกี่ยวกับการเปลี่ยนแปลงสถานะวงจรทั้งหมดในคอนโซลของนักพัฒนาซอฟต์แวร์ ซึ่งน่าจะช่วยในการแก้ไขข้อบกพร่องที่ทำให้สิ่งต่างๆ ไม่เป็นไปตามที่คุณคาดหวัง
นอกจากนี้ ข้อผิดพลาดที่นักพัฒนาซอฟต์แวร์มักจะทำเมื่อใช้ Service Worker เป็นครั้งแรกคือการลงทะเบียน Service Worker ที่อยู่ในขอบเขตที่ไม่ถูกต้อง
คลาส Workbox
จะเตือนคุณหากหน้าเว็บที่ลงทะเบียน Service Worker ไม่อยู่ในขอบเขตของ Service Worker เพื่อป้องกันไม่ให้เกิดเหตุการณ์ดังกล่าว และจะเตือนคุณในกรณีที่ Service Worker ทำงานอยู่แต่ยังไม่ได้ควบคุมหน้า
การสื่อสารจากหน้าต่างสู่บริการผู้ปฏิบัติงาน
การใช้งาน Service Worker ขั้นสูงที่สุดจะมีการรับส่งข้อความจำนวนมากระหว่างโปรแกรมทำงานของบริการและหน้าต่าง คลาส Workbox
ช่วยในเรื่องนี้ได้เหมือนกันโดยมอบเมธอด messageSW()
ซึ่งจะ postMessage()
โปรแกรมทำงานของบริการที่ลงทะเบียนของอินสแตนซ์และรอการตอบกลับ
แม้ว่าคุณจะสามารถส่งข้อมูลไปยังโปรแกรมทำงานของบริการในรูปแบบใดก็ได้ แต่รูปแบบที่แชร์โดยแพ็กเกจ Workbox ทั้งหมดจะเป็นออบเจ็กต์ที่มี 3 พร็อพเพอร์ตี้ (2 ตัวเลือกหลังเป็นตัวเลือก) ดังนี้
ข้อความที่ส่งผ่านเมธอด messageSW()
จะใช้ MessageChannel
เพื่อให้ผู้รับตอบกลับได้ หากต้องการตอบกลับข้อความ ให้โทรหา event.ports[0].postMessage(response)
ใน Listener เหตุการณ์ เมธอด messageSW()
จะส่งคืนสัญญาว่าจะแก้ไขให้กับ response
ใดก็ตามที่คุณตอบกลับ
ต่อไปนี้เป็นตัวอย่างการส่งข้อความจากหน้าต่างไปยัง Service Worker และการได้รับการตอบกลับ โค้ดบล็อกแรกคือ Listener ข้อความใน Service Worker และบล็อกที่ 2 ใช้คลาส Workbox
เพื่อส่งข้อความและรอการตอบกลับ ดังนี้
โค้ดใน sw.js:
const SW_VERSION = '1.0.0';
addEventListener('message', event => {
if (event.data.type === 'GET_VERSION') {
event.ports[0].postMessage(SW_VERSION);
}
});
โค้ดใน main.js (ทำงานในหน้าต่าง):
const wb = new Workbox('/sw.js');
wb.register();
const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);
การจัดการความไม่เข้ากันของเวอร์ชัน
ตัวอย่างด้านบนแสดงวิธีที่คุณใช้การตรวจสอบเวอร์ชัน Service Worker จากหน้าต่าง เราใช้ตัวอย่างนี้เนื่องจากเมื่อคุณส่งข้อความกลับไปกลับมาระหว่างหน้าต่างและ Service Worker คุณควรทราบว่า Service Worker อาจไม่ได้ใช้งานเว็บไซต์เวอร์ชันเดียวกับที่โค้ดของหน้าเว็บทำงานอยู่ และวิธีแก้ปัญหานี้ขึ้นอยู่กับว่าคุณแสดงหน้าเว็บโดยเน้นเครือข่ายหรือเน้นแคชเป็นหลัก
เครือข่ายก่อน
เมื่อแสดงเครือข่ายหน้าเว็บก่อน ผู้ใช้จะได้รับ HTML เวอร์ชันล่าสุดจากเซิร์ฟเวอร์ของคุณเสมอ อย่างไรก็ตาม ครั้งแรกที่ผู้ใช้เข้าชมเว็บไซต์อีกครั้ง (หลังจากที่คุณทำให้การอัปเดตใช้งานได้) HTML ที่ผู้ใช้ได้รับจะเป็นเวอร์ชันล่าสุด แต่โปรแกรมทำงานของบริการที่ทำงานในเบราว์เซอร์ของตนจะเป็นเวอร์ชันที่ติดตั้งก่อนหน้านี้ (อาจเป็นเวอร์ชันเก่าหลายเวอร์ชัน)
คุณต้องทำความเข้าใจเกี่ยวกับความเป็นไปได้นี้ เพราะหาก JavaScript ที่โหลดโดยเวอร์ชันปัจจุบันของหน้าส่งข้อความถึง Service Worker เวอร์ชันเก่า เวอร์ชันนั้นอาจไม่รู้ว่าต้องตอบสนองอย่างไร (หรืออาจตอบสนองด้วยรูปแบบที่เข้ากันไม่ได้)
ด้วยเหตุนี้ คุณจึงควรกำหนดเวอร์ชัน Service Worker ไว้ทุกครั้งและตรวจสอบเวอร์ชันที่เข้ากันได้ก่อนที่จะทำงานสำคัญ
ตัวอย่างเช่น ในโค้ดด้านบน หากเวอร์ชันของ Service Worker กลับมาโดยการเรียก messageSW()
นั้นเก่ากว่าเวอร์ชันที่คาดไว้ คุณควรรอจนกว่าจะพบอัปเดต (ซึ่งจะเกิดขึ้นเมื่อเรียกใช้ register()
) เมื่อถึงจุดนี้ คุณสามารถแจ้งให้ผู้ใช้ทราบหรืออัปเดต หรือจะข้ามขั้นตอนการรอเพื่อเปิดใช้งานบริการใหม่ทันทีก็ได้
แคชก่อน
เมื่อแสดงแคชของหน้าเว็บเป็นอันดับแรก คุณจะทราบว่าในช่วงแรกหน้าเว็บจะเป็นเวอร์ชันเดียวกับ Service Worker เสมอ (เพราะเป็นการแสดงผลหน้าเว็บ) ซึ่งตรงข้ามกับเมื่อแสดงหน้าเว็บเป็นอันดับแรกในเครือข่าย ด้วยเหตุนี้ การใช้ messageSW()
ทันที
จึงปลอดภัย
อย่างไรก็ตาม หากพบ Service Worker เวอร์ชันที่อัปเดตแล้วและเปิดใช้งานเมื่อหน้าเว็บเรียกใช้ register()
(กล่าวคือ คุณตั้งใจข้ามขั้นตอนการรอ) การส่งข้อความถึงโปรแกรมดังกล่าวอาจไม่ปลอดภัยอีกต่อไป
กลยุทธ์หนึ่งในการจัดการความเป็นไปได้นี้คือการใช้รูปแบบการกำหนดเวอร์ชันที่ช่วยให้คุณแยกความแตกต่างระหว่างการอัปเดตที่ด่วนกับการอัปเดตที่ไม่สำคัญ และในกรณีที่มีการอัปเดตที่เสียหาย คุณจะทราบว่าการส่งข้อความถึงโปรแกรมทำงานของบริการนั้นไม่ปลอดภัย แต่คุณควรเตือนผู้ใช้ว่ากำลังใช้หน้าเวอร์ชันเก่าอยู่ และแนะนำให้ผู้ใช้โหลดซ้ำเพื่อรับการอัปเดต
ข้ามตัวช่วยในการรอ
รูปแบบการใช้งานทั่วไปสำหรับการรับส่งข้อความจาก Window to Service Worker คือการส่งข้อความ {type: 'SKIP_WAITING'}
เพื่อบอกให้ Service Worker ที่ติดตั้ง
ข้ามขั้นตอนการรอและเปิดใช้งาน
ตั้งแต่ Workbox v6 เป็นต้นไป คุณจะใช้เมธอด messageSkipWaiting()
เพื่อส่งข้อความ {type: 'SKIP_WAITING'}
ไปยัง Service Worker รอที่เชื่อมโยงกับการลงทะเบียน Service Worker ปัจจุบันได้ โปรแกรมจะไม่ทำงานเงียบๆ หากไม่มี Service Worker รออยู่
ประเภท
Workbox
คลาสที่จะช่วยจัดการการลงทะเบียน การอัปเดต และการดำเนินการกับเหตุการณ์ในวงจรการทำงานของโปรแกรมทำงานของบริการ
พร็อพเพอร์ตี้
-
เครื่องมือสร้าง
void
สร้างอินสแตนซ์ Workbox ใหม่ด้วย URL สคริปต์และตัวเลือกโปรแกรมทำงานของบริการ URL ของสคริปต์และตัวเลือกจะเหมือนกับ URL ที่ใช้เมื่อเรียกใช้ navigator.serviceWorker.register(scriptURL, options)
ฟังก์ชัน
constructor
มีลักษณะดังนี้(scriptURL: string | TrustedScriptURL, registerOptions?: object) => {...}
-
scriptURL
สตริง | TrustedScriptURL
สคริปต์ Service Worker ที่เชื่อมโยงกับอินสแตนซ์นี้ รองรับการใช้
TrustedScriptURL
-
registerOptions
ออบเจ็กต์ ไม่บังคับ
-
returns
-
-
ใช้งาน
Promise<ServiceWorker>
-
กำลังควบคุม
Promise<ServiceWorker>
-
getSW
void
แก้ไขโดยมีการอ้างอิงไปยัง Service Worker ที่ตรงกับ URL สคริปต์ของอินสแตนซ์นี้ทันทีที่พร้อมใช้งาน
ณ เวลาลงทะเบียน หากมีโปรแกรมทำงานของบริการที่กำลังทำงานอยู่หรือกำลังรอซึ่งมี URL ของสคริปต์ที่ตรงกันอยู่แล้ว ระบบจะใช้โปรแกรมทำงานดังกล่าว (โดยที่โปรแกรมทำงานของบริการรอจะมีลำดับความสำคัญมากกว่าโปรแกรมทำงานของบริการที่ใช้งานอยู่หากตรงกันทั้งสองรายการ เนื่องจากโปรแกรมทำงานของบริการที่รออยู่เพิ่งลงทะเบียนไปเมื่อเร็วๆ นี้) หากไม่มี Service Worker ที่ใช้งานอยู่หรือที่รออยู่ที่ตรงกัน ณ เวลาที่ลงทะเบียน สัญญาจะไม่แก้ไขจนกว่าจะพบการอัปเดตและเริ่มการติดตั้ง ซึ่งเป็นจุดที่มีการใช้ Service Worker ที่ติดตั้ง
ฟังก์ชัน
getSW
มีลักษณะดังนี้() => {...}
-
returns
Promise<ServiceWorker>
-
-
messageSW
void
ส่งออบเจ็กต์ข้อมูลที่ส่งผ่านไปยัง Service Worker ที่ลงทะเบียนไว้โดยอินสแตนซ์นี้ (ผ่าน
workbox-window.Workbox#getSW
) และแก้ไขด้วยการตอบกลับ (หากมี)คุณตั้งค่าการตอบกลับได้ในเครื่องจัดการข้อความใน Service Worker โดยเรียกใช้
event.ports[0].postMessage(...)
ซึ่งจะแก้ไขคำสัญญาที่messageSW()
ส่งคืน หากไม่มีการตอบกลับ คำสัญญาจะไม่มีทางแก้ปัญหาสำเร็จฟังก์ชัน
messageSW
มีลักษณะดังนี้(data: object) => {...}
-
ข้อมูล
ออบเจ็กต์
ออบเจ็กต์ที่จะส่งไปยัง Service Worker
-
returns
คำสัญญา<any>
-
-
messageSkipWaiting
void
ส่งข้อความ
{type: 'SKIP_WAITING'}
ไปยัง Service Worker ที่ตอนนี้อยู่ในสถานะwaiting
ซึ่งเชื่อมโยงกับการลงทะเบียนปัจจุบันหากไม่มีการลงทะเบียนปัจจุบันหรือไม่มี Service Worker คือ
waiting
การเรียกใช้ดังกล่าวจะไม่มีผลใดๆฟังก์ชัน
messageSkipWaiting
มีลักษณะดังนี้() => {...}
-
register
void
ลงทะเบียนโปรแกรมทำงานของบริการสำหรับ URL สคริปต์ของอินสแตนซ์นี้และตัวเลือกผู้ปฏิบัติงานบริการ โดยค่าเริ่มต้น วิธีนี้จะทำให้การลงทะเบียนล่าช้าลงจนกว่าจะโหลดหน้าต่างแล้ว
ฟังก์ชัน
register
มีลักษณะดังนี้(options?: object) => {...}
-
ตัวเลือก
ออบเจ็กต์ ไม่บังคับ
-
ที่อยู่ติดๆ กัน
บูลีน ไม่บังคับ
-
-
returns
Promise<ServiceWorkerRegistration>
-
-
อัปเดต
void
ตรวจหาการอัปเดตสำหรับ Service Worker ที่ลงทะเบียนไว้
ฟังก์ชัน
update
มีลักษณะดังนี้() => {...}
-
returns
Promise<void>
-
WorkboxEventMap
พร็อพเพอร์ตี้
-
เปิดอยู่
-
กำลังเปิดใช้งาน
-
กำลังควบคุม
-
ติดตั้งแล้ว
-
กำลังติดตั้ง
-
ข้อความ
-
ซ้ำซ้อน
-
กำลังรอ
WorkboxLifecycleEvent
พร็อพเพอร์ตี้
-
isExternal
บูลีน ไม่บังคับ
-
isUpdate
บูลีน ไม่บังคับ
-
originalEvent
กิจกรรม ไม่บังคับ
-
sw
ServiceWorker ไม่บังคับ
-
เป้าหมาย
WorkboxEventTarget ไม่บังคับ
-
ประเภท
typeOperator
WorkboxLifecycleEventMap
พร็อพเพอร์ตี้
-
เปิดอยู่
-
กำลังเปิดใช้งาน
-
กำลังควบคุม
-
ติดตั้งแล้ว
-
กำลังติดตั้ง
-
ซ้ำซ้อน
-
กำลังรอ
WorkboxLifecycleWaitingEvent
พร็อพเพอร์ตี้
-
isExternal
บูลีน ไม่บังคับ
-
isUpdate
บูลีน ไม่บังคับ
-
originalEvent
กิจกรรม ไม่บังคับ
-
sw
ServiceWorker ไม่บังคับ
-
เป้าหมาย
WorkboxEventTarget ไม่บังคับ
-
ประเภท
typeOperator
-
wasWaitingBeforeRegister
บูลีน ไม่บังคับ
WorkboxMessageEvent
พร็อพเพอร์ตี้
-
ข้อมูล
อะไรก็ได้
-
isExternal
บูลีน ไม่บังคับ
-
originalEvent
เหตุการณ์
-
ports
typeOperator
-
sw
ServiceWorker ไม่บังคับ
-
เป้าหมาย
WorkboxEventTarget ไม่บังคับ
-
ประเภท
วิธีการ
messageSW()
workbox-window.messageSW(
sw: ServiceWorker,
data: object,
)
ส่งออบเจ็กต์ข้อมูลไปยัง Service Worker ผ่าน postMessage
และแก้ไขด้วยการตอบกลับ (หากมี)
คุณตั้งค่าการตอบกลับได้ในเครื่องจัดการข้อความใน Service Worker โดยเรียกใช้ event.ports[0].postMessage(...)
ซึ่งจะแก้ไขคำสัญญาที่ messageSW()
ส่งคืน หากไม่มีการตั้งค่าการตอบสนอง
คำสัญญาจะไม่หายไป
พารามิเตอร์
-
sw
ServiceWorker
Service Worker ที่จะส่งข้อความไปให้
-
ข้อมูล
ออบเจ็กต์
ออบเจ็กต์ที่จะส่งไปยัง Service Worker
การคืนสินค้า
-
คำสัญญา<any>