การที่จะรู้ว่าผู้ปฏิบัติงานบริการกำลังทำอะไรอยู่นั้นเป็นเรื่องยากหากไม่เข้าใจวงจรชีวิตของผู้ใช้ การทำงานภายในของพวกเขาดูไม่ชัดเจน แม้จะไม่มีกฎเกณฑ์ก็ตาม อย่าลืมว่าระบบได้กำหนดลักษณะการทำงานของโปรแกรมทำงานของบริการไว้อย่างดี เช่นเดียวกับ API อื่นๆ ของเบราว์เซอร์ ที่กำหนดและทำให้แอปพลิเคชันแบบออฟไลน์เป็นไปได้ ในขณะเดียวกันก็อำนวยความสะดวกในการอัปเดตโดยไม่รบกวนประสบการณ์ของผู้ใช้
ก่อนเข้าสู่ Workbox คุณต้องเข้าใจวงจรการทำงานของโปรแกรมทำงานของบริการเพื่อให้สิ่งที่ Workbox ทำได้อย่างเหมาะสม
การให้คำจำกัดความ
ก่อนเข้าสู่วงจรชีวิตของโปรแกรมทำงานของบริการ คุณควรกำหนดคำบางคำเกี่ยวกับการทำงานของวงจรนั้น
การควบคุมและขอบเขต
แนวคิดเกี่ยวกับการควบคุมมีความสำคัญอย่างยิ่งต่อการทำความเข้าใจวิธีการทำงานของโปรแกรมทำงานของบริการ หน้าที่โปรแกรมทำงานของบริการระบุว่าควบคุมได้คือหน้าที่อนุญาตให้โปรแกรมทำงานของบริการสกัดกั้นคำขอเครือข่ายในนามของตนเองได้ มี Service Worker และทำงานให้กับหน้าเว็บในขอบเขตที่กำหนดได้
ขอบเขต
ขอบเขตของ Service Worker จะกำหนดจากตำแหน่งของผู้ใช้ในเว็บเซิร์ฟเวอร์
หากโปรแกรมทำงานของบริการทำงานในหน้าที่ /subdir/index.html
และอยู่ที่ /subdir/sw.js
ขอบเขตของโปรแกรมทำงานของบริการคือ /subdir/
หากต้องการดูแนวคิดของขอบเขตในการใช้งานจริง ลองดูตัวอย่างนี้
- นำทางไปยัง
https://service-worker-scope-viewer.glitch.me/subdir/index.html.
ข้อความจะปรากฏขึ้นเพื่อแจ้งว่าไม่มี Service Worker กำลังควบคุมหน้านี้อยู่
แต่หน้าดังกล่าวจะมีการลงทะเบียน Service Worker จาก
https://service-worker-scope-viewer.glitch.me/subdir/sw.js
- โหลดหน้าเว็บซ้ำ เนื่องจากมีการลงทะเบียน Service Worker แล้วและมีการใช้งานอยู่ ก็ทำการควบคุมหน้าอยู่ แบบฟอร์มที่มีขอบเขตของโปรแกรมทำงานของบริการ สถานะปัจจุบัน และ URL จะปรากฏ หมายเหตุ: การโหลดหน้าซ้ำไม่มีความเกี่ยวข้องใดๆ กับขอบเขต แต่เป็นวงจรของ Service Worker ซึ่งจะอธิบายในภายหลัง
- ไปที่ https://service-worker-scope-viewer.glitch.me/index.html แม้ว่าจะมีการลงทะเบียน Service Worker ในต้นทางนี้แล้ว ยังมีข้อความแจ้งว่าไม่มี Service Worker อยู่ในขณะนี้ เนื่องจากหน้านี้ไม่ได้อยู่ในขอบเขตของ Service Worker ที่ลงทะเบียน
ขอบเขตจะจำกัดหน้าที่ควบคุมของ Service Worker
ในตัวอย่างนี้ หมายความว่า Service Worker ที่โหลดจาก /subdir/sw.js
จะควบคุมได้เฉพาะหน้าที่อยู่ใน /subdir/
หรือแผนผังย่อยเท่านั้น
วิธีการข้างต้นคือวิธีการทำงานของการกำหนดขอบเขตโดยค่าเริ่มต้น
แต่ขอบเขตสูงสุดที่อนุญาต คุณสามารถลบล้างได้โดยการตั้งค่า
ส่วนหัวการตอบกลับ Service-Worker-Allowed
รวมถึงการส่ง
ตัวเลือก scope
เป็นเมธอด register
หากไม่มีเหตุผลที่ดีในการจำกัดขอบเขตของ Service Worker ไว้เฉพาะต้นทางบางส่วน
โหลด Service Worker จากไดเรกทอรีรากของเว็บเซิร์ฟเวอร์เพื่อให้ขอบเขตกว้างที่สุดเท่าที่จะเป็นไปได้
และไม่ต้องกังวลเกี่ยวกับส่วนหัว Service-Worker-Allowed
ทำให้คนอื่นๆ ใช้งานได้ง่ายขึ้นมาก
ลูกค้า
เมื่อมีการระบุว่า Service Worker กำลังควบคุมหน้าเว็บ จริงๆ แล้วเป็นการควบคุมไคลเอ็นต์
ไคลเอ็นต์คือหน้าเว็บที่เปิดอยู่ซึ่งมี URL อยู่ภายในขอบเขตของ Service Worker นั้น
โดยเฉพาะอย่างยิ่ง ต่อไปนี้คือตัวอย่างของ WindowClient
วงจรของโปรแกรมทำงานของบริการใหม่
หากต้องการให้โปรแกรมทำงานของบริการควบคุมหน้าได้ สิ่งนั้นจะต้องเกิดขึ้นจริงก่อน จึงจะพูดได้ว่า เรามาเริ่มจากสิ่งที่จะเกิดขึ้นเมื่อมีการนำ Service Worker รายใหม่ไปใช้กับเว็บไซต์ที่ไม่มีโปรแกรมทำงานของบริการ (Service Worker) ที่ใช้งานอยู่
การลงทะเบียน
การลงทะเบียนเป็นขั้นตอนเริ่มต้นของวงจรการทำงานของโปรแกรมทำงานของบริการ
<!-- In index.html, for example: -->
<script>
// Don't register the service worker
// until the page has fully loaded
window.addEventListener('load', () => {
// Is service worker available?
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then(() => {
console.log('Service worker registered!');
}).catch((error) => {
console.warn('Error registering service worker:');
console.warn(error);
});
}
});
</script>
โค้ดนี้จะทำงานในเทรดหลักและดำเนินการต่อไปนี้
- เนื่องจากการเข้าชมเว็บไซต์ครั้งแรกของผู้ใช้จะเกิดขึ้นโดยไม่มี Service Worker ที่ลงทะเบียนไว้ ให้รอจนกว่าหน้าจะโหลดเสร็จสมบูรณ์ก่อนลงทะเบียน เพื่อไม่ให้เกิดการช่วงชิงแบนด์วิดท์เมื่อ Service Worker แคชข้อมูลไว้ล่วงหน้า
- แม้ว่า Service Worker จะมีการสนับสนุนเป็นอย่างดี การตรวจสอบอย่างรวดเร็วจะช่วยหลีกเลี่ยงข้อผิดพลาดในเบราว์เซอร์ที่ระบบไม่รองรับ
- เมื่อหน้าเว็บโหลดเสร็จแล้ว และลงทะเบียน
/sw.js
หากระบบรองรับ Service Worker
สิ่งสำคัญที่ควรทำความเข้าใจมีดังนี้
- Service Worker คือ ใช้ได้เฉพาะใน HTTPS หรือ localhost
- หากเนื้อหาของโปรแกรมทำงานของบริการมีข้อผิดพลาดทางไวยากรณ์ ลงทะเบียนไม่สำเร็จและระบบจะทิ้ง Service Worker
- โปรดทราบ: Service Worker ทำงานภายในขอบเขตที่กำหนด ในที่นี้ ขอบเขตคือต้นทางทั้งหมด เนื่องจากโหลดจากไดเรกทอรีราก
- เมื่อเริ่มการลงทะเบียน สถานะของ Service Worker จะตั้งค่าเป็น
'installing'
เมื่อการลงทะเบียนเสร็จสิ้น การติดตั้งจะเริ่มขึ้น
การติดตั้ง
Service Worker เริ่มทำงาน
install
กิจกรรมหลังการลงทะเบียน
จะมีการเรียกใช้ install
เพียงครั้งเดียวต่อ Service Worker และจะไม่เริ่มทำงานอีกจนกว่าจะได้รับการอัปเดต
ระบบสามารถลงทะเบียนการติดต่อกลับสำหรับเหตุการณ์ install
ในขอบเขตผู้ปฏิบัติงานด้วย addEventListener
ได้ ดังนี้
// /sw.js
self.addEventListener('install', (event) => {
const cacheKey = 'MyFancyCacheName_v1';
event.waitUntil(caches.open(cacheKey).then((cache) => {
// Add all the assets in the array to the 'MyFancyCacheName_v1'
// `Cache` instance for later use.
return cache.addAll([
'/css/global.bc7b80b7.css',
'/css/home.fe5d0b23.css',
'/js/home.d3cc4ba4.js',
'/js/jquery.43ca4933.js'
]);
}));
});
การดำเนินการนี้จะสร้างอินสแตนซ์ Cache
ใหม่และแคชเนื้อหาล่วงหน้า
เรามีโอกาสมากมายที่จะได้พูดถึงการแคชล่วงหน้าในภายหลัง
ตอนนี้เรามาดูที่บทบาทของ
event.waitUntil
event.waitUntil
รับคำมั่นสัญญา
และรอจนกว่าสัญญาดังกล่าวจะได้รับการแก้ไข
ในตัวอย่างนี้ สัญญาดังกล่าวจะทำสิ่งที่ไม่พร้อมกัน 2 อย่าง
- สร้างอินสแตนซ์
Cache
ใหม่ชื่อ'MyFancyCache_v1'
- หลังจากสร้างแคชแล้ว
อาร์เรย์ของ URL เนื้อหาได้รับการแคชล่วงหน้าโดยใช้แบบไม่พร้อมกัน
addAll
วิธี
การติดตั้งล้มเหลวหากมีการส่งคำสัญญาไปยัง event.waitUntil
คือ
ถูกปฏิเสธ
ในกรณีนี้ ระบบจะทิ้ง Service Worker
หากสัญญาไว้ได้รับการแก้ไขแล้ว
การติดตั้งสำเร็จและสถานะของโปรแกรมทำงานของบริการจะเปลี่ยนเป็น 'installed'
จากนั้นจะเปิดใช้งาน
การดำเนินการ
หากการลงทะเบียนและติดตั้งสำเร็จ
โปรแกรมทำงานของบริการจะเปิดใช้งาน และสถานะของโปรแกรมจะกลายเป็น 'activating'
งานสามารถดำเนินการได้ในระหว่างการเปิดใช้งานในโปรแกรมทำงานของบริการ
activate
เหตุการณ์
งานทั่วไปในเหตุการณ์นี้ก็คือการพรรณาแคชเก่า
แต่สำหรับโปรแกรมทำงานของบริการใหม่
ไม่เกี่ยวข้องกับตอนนี้
และจะขยายการใช้งานเมื่อเราพูดคุยเกี่ยวกับการอัปเดตโปรแกรมทำงานของบริการ
สำหรับโปรแกรมทำงานของบริการใหม่ activate
จะเริ่มทำงานทันทีหลังจากที่ install
สำเร็จ
เมื่อการเปิดใช้งานเสร็จสิ้น
สถานะของโปรแกรมทำงานของบริการจะกลายเป็น 'activated'
ให้สังเกตว่าโดยค่าเริ่มต้น
Service Worker ใหม่จะไม่เริ่มควบคุมหน้าจนกว่าจะถึงการนำทางครั้งถัดไปหรือการรีเฟรชหน้าเว็บ
การจัดการการอัปเดต Service Worker
เมื่อทำให้ Service Worker รายแรกใช้งานได้แล้ว เราน่าจะต้องมีการอัปเดตในภายหลัง ตัวอย่างเช่น อาจต้องมีการอัปเดตหากมีการเปลี่ยนแปลงในการจัดการคำขอหรือตรรกะการแคชล่วงหน้า
เมื่อมีการอัปเดต
เบราว์เซอร์จะตรวจหาการอัปเดตของ Service Worker ในกรณีต่อไปนี้
- ผู้ใช้ไปยังหน้าเว็บภายในขอบเขตของ Service Worker
navigator.serviceWorker.register()
จะได้รับการเรียกด้วย URL ที่แตกต่างจาก Service Worker ที่ติดตั้งไว้ในปัจจุบัน แต่อย่าเปลี่ยน URL ของ Service Workernavigator.serviceWorker.register()
ด้วย URL เดียวกันกับ Service Worker ที่ติดตั้งไว้ แต่ใช้ขอบเขตต่างกัน ขอย้ำอีกครั้งว่าให้หลีกเลี่ยงปัญหานี้โดยคงขอบเขตไว้ที่รูทของต้นทาง หากเป็นไปได้- เมื่อเกิดเหตุการณ์ต่างๆ เช่น
'push'
หรือ'sync'
มีการทริกเกอร์ภายใน 24 ชั่วโมงที่ผ่านมา แต่ไม่ต้องกังวลกับเหตุการณ์เหล่านี้
การอัปเดตเกิดขึ้นได้อย่างไร
หากทราบว่าเวลาที่เบราว์เซอร์อัปเดตโปรแกรมทำงานของบริการมีความสำคัญ แต่ "วิธีการ" ก็คือ ในกรณีที่ URL หรือขอบเขตของโปรแกรมทำงานของบริการไม่มีการเปลี่ยนแปลง โปรแกรมทำงานของบริการที่ติดตั้งอยู่ในขณะนี้จะอัปเดตเป็นเวอร์ชันใหม่เท่านั้นเมื่อมีการเปลี่ยนแปลงเนื้อหา
โดยเบราว์เซอร์จะตรวจหาการเปลี่ยนแปลงด้วยวิธีต่อไปนี้
- การเปลี่ยนแปลงแบบไบต์ต่อไบต์ในสคริปต์ที่ขอโดย
importScripts
หากมี - การเปลี่ยนแปลงโค้ดระดับบนสุดของโปรแกรมทำงานของบริการ ซึ่งส่งผลต่อลายนิ้วมือที่เบราว์เซอร์สร้างขึ้น
เบราว์เซอร์มีภาระงานมากมาย เพื่อให้เบราว์เซอร์มีทุกสิ่งที่ต้องใช้ในการตรวจหาการเปลี่ยนแปลงเนื้อหาของ Service Worker ได้อย่างน่าเชื่อถือ อย่าบอกแคช HTTP ให้เก็บแคชดังกล่าว และอย่าเปลี่ยนชื่อไฟล์ เบราว์เซอร์จะตรวจสอบการอัปเดตโดยอัตโนมัติเมื่อมีการไปยังหน้าใหม่ภายในขอบเขตของ Service Worker
เรียกใช้การตรวจสอบการอัปเดตด้วยตนเอง
เกี่ยวกับการอัปเดตที่น่าเป็นห่วง แต่ตรรกะการลงทะเบียนมักไม่ควรเปลี่ยนแปลง แต่ข้อยกเว้นหนึ่งอาจเป็นกรณีที่เซสชันในเว็บไซต์มีระยะเวลานาน ซึ่งเกิดขึ้นได้ในแอปพลิเคชันหน้าเว็บเดียวซึ่ง คำขอการนำทางนั้นเกิดขึ้นได้ยาก เนื่องจากโดยปกติแล้วแอปพลิเคชันจะพบกับคำขอการนำทาง 1 คำขอในช่วงเริ่มต้นวงจรของแอปพลิเคชัน ในสถานการณ์เช่นนี้ ระบบอาจเรียกใช้การอัปเดตด้วยตนเองในเทรดหลัก ดังนี้
navigator.serviceWorker.ready.then((registration) => {
registration.update();
});
สำหรับเว็บไซต์แบบดั้งเดิม หรือในกรณีที่เซสชันของผู้ใช้ไม่ได้ มีระยะเวลานาน อาจไม่จำเป็นที่จะต้องทริกเกอร์การอัปเดตด้วยตนเอง
การติดตั้ง
เมื่อใช้ Bundler สร้างเนื้อหาแบบคงที่
เนื้อหาเหล่านั้นจะมีแฮชในชื่อ
เช่น framework.3defa9d2.js
สมมติว่าเนื้อหาบางส่วนได้รับการแคชล่วงหน้าสำหรับการเข้าถึงแบบออฟไลน์ในภายหลัง
การดำเนินการนี้จะต้องมีการอัปเดต Service Worker เพื่อแคชเนื้อหาที่อัปเดตไว้ล่วงหน้า
self.addEventListener('install', (event) => {
const cacheKey = 'MyFancyCacheName_v2';
event.waitUntil(caches.open(cacheKey).then((cache) => {
// Add all the assets in the array to the 'MyFancyCacheName_v2'
// `Cache` instance for later use.
return cache.addAll([
'/css/global.ced4aef2.css',
'/css/home.cbe409ad.css',
'/js/home.109defa4.js',
'/js/jquery.38caf32d.js'
]);
}));
});
มี 2 สิ่งที่แตกต่างจากตัวอย่างเหตุการณ์ install
แรกจากก่อนหน้านี้
- สร้างอินสแตนซ์
Cache
ใหม่ที่มีคีย์'MyFancyCacheName_v2'
แล้ว - มีการเปลี่ยนแปลงชื่อเนื้อหาที่แคชล่วงหน้า
สิ่งหนึ่งที่ควรทราบคือจะมีการติดตั้ง Service Worker ที่อัปเดตควบคู่ไปกับโปรแกรมทำงานก่อนหน้า ซึ่งหมายความว่าโปรแกรมทำงานของบริการเดิมจะยังคงควบคุมหน้าที่เปิดอยู่และหลังจากการติดตั้ง รหัสใหม่จะเข้าสู่สถานะรอจนกว่าจะมีการเปิดใช้งาน
โดยค่าเริ่มต้น โปรแกรมทำงานของบริการใหม่จะเปิดใช้งานเมื่อไม่มีไคลเอ็นต์เดิมที่ควบคุมโดยโปรแกรมทำงานเดิม ข้อผิดพลาดนี้จะเกิดขึ้นเมื่อปิดแท็บที่เปิดอยู่ทั้งหมดของเว็บไซต์ที่เกี่ยวข้อง
การดำเนินการ
เมื่อติดตั้ง Service Worker ที่อัปเดตแล้วและระยะรอสิ้นสุด
โปรแกรมจะทำงาน และระบบจะทิ้ง Service Worker เดิม
งานทั่วไปที่ต้องทำในเหตุการณ์ activate
ของ Service Worker ที่อัปเดตคือการลบแคชเก่า
นำแคชเก่าออกโดยรับคีย์สำหรับอินสแตนซ์ Cache
ที่เปิดอยู่ทั้งหมด
caches.keys
และลบแคชที่ไม่อยู่ในรายการอนุญาตที่กำหนด
caches.delete
:
self.addEventListener('activate', (event) => {
// Specify allowed cache keys
const cacheAllowList = ['MyFancyCacheName_v2'];
// Get all the currently active `Cache` instances.
event.waitUntil(caches.keys().then((keys) => {
// Delete all caches that aren't in the allow list:
return Promise.all(keys.map((key) => {
if (!cacheAllowList.includes(key)) {
return caches.delete(key);
}
}));
}));
});
แคชเก่าๆ ไม่จำเป็นต้องจัดการให้เป็นระเบียบ
เราจำเป็นต้องดำเนินการดังกล่าวด้วยตัวเอง ไม่เช่นนั้น
โควต้าพื้นที่เก็บข้อมูล
เนื่องจาก 'MyFancyCacheName_v1'
จาก Service Worker รายแรกล้าสมัย
รายการที่อนุญาตสำหรับการแคชจะได้รับการอัปเดตเพื่อระบุ 'MyFancyCacheName_v2'
ซึ่งจะลบแคชที่ใช้ชื่ออื่น
เหตุการณ์ activate
จะเสร็จสิ้นหลังจากนำแคชเก่าออกแล้ว
ในจุดนี้ Service Worker ใหม่จะเข้าควบคุมหน้านี้
แทนที่อันเก่าในที่สุด
วงจรชีวิตต้องดำเนินต่อไป
มีการใช้ Workbox เพื่อจัดการการติดตั้งใช้งานและการอัปเดตของ Service Worker หรือไม่ หรือใช้ Service Worker API โดยตรง การทำความเข้าใจวงจรชีวิตของโปรแกรมทำงานของบริการ ในการทำความเข้าใจนี้ พฤติกรรมของผู้ปฏิบัติงานบริการควรดูสมเหตุสมผลมากกว่าที่ลึกลับ
สำหรับผู้ที่สนใจเจาะลึกในหัวข้อนี้ คุณควรไปลอง บทความนี้โดย Jake Archibald มีข้อจำกัดเล็กๆ น้อยๆ มากมาย เกี่ยวกับการเต้นตลอดวงจรของบริการ แต่เป็นสิ่งที่รู้ได้จริง และความรู้ดังกล่าวจะมีประสิทธิภาพมากขึ้นเมื่อใช้ Workbox