วิธีคิดเมื่อนึกถึงโปรแกรมทำงานของบริการ
โปรแกรมทำงานของบริการมีประสิทธิภาพและคุ้มค่าอย่างยิ่งกับการเรียนรู้ ซึ่งช่วยให้คุณมอบประสบการณ์ที่ไม่เคยมีมาก่อนให้กับผู้ใช้ เว็บไซต์ของคุณจะโหลดได้ทันที ทำงานได้แบบออฟไลน์ คุณสามารถติดตั้งเป็นแอปสำหรับแพลตฟอร์มโดยเฉพาะและให้ความรู้สึกสวยงามเหมือนแอปที่เคยเข้าถึงได้ แต่เข้าถึงและอยู่ในเว็บได้อย่างอิสระ
แต่ Service Worker นั้นไม่เหมือนกับนักพัฒนาซอฟต์แวร์เว็บส่วนใหญ่ที่เราคุ้นเคย โดยมาพร้อมกับเส้นทางการเรียนรู้ที่สูงชันและอุปสรรคต่างๆ ที่คุณต้องระวัง
ฉันและ Google Developers เพิ่งจะทำงานร่วมกันในโปรเจ็กต์ Service Workies ซึ่งเป็นเกมฟรีสำหรับทำความเข้าใจโปรแกรมทำงานของบริการ ระหว่างสร้างและทำงานร่วมกับโปรแกรมทำงานส่วนที่ซับซ้อนและพบอุปสรรคเล็กน้อย สิ่งที่ช่วยผมได้มากที่สุดก็คือ คำอุปมาอุปไมยที่แสดงภาพความคล้ายคลึงกันจำนวนหนึ่ง ในโพสต์นี้ เราจะมาดูแบบจำลองทางจิตใจเหล่านี้และสรุปความคิดของเราเกี่ยวกับลักษณะนิสัยที่ไม่ธรรมดาที่ทำให้พนักงานบริการทั้งซับซ้อนและยอดเยี่ยม
เหมือนกัน แต่แตกต่างกัน
ขณะเขียนโค้ด Service Worker หลายสิ่งหลายอย่างจะรู้สึกคุ้นเคย คุณจะได้ใช้ฟีเจอร์ภาษา JavaScript ใหม่ๆ ที่ชื่นชอบ คุณฟังเหตุการณ์ในวงจรเช่นเดียวกับเหตุการณ์ UI คุณสามารถจัดการขั้นตอนการควบคุมด้วยคำสัญญาอย่างที่คุณคุ้นเคย
แต่พฤติกรรมอื่นๆ ของโปรแกรมทำงานของบริการทำให้คุณเกาหัวด้วยความสับสน โดยเฉพาะอย่างยิ่งเมื่อคุณรีเฟรชหน้าเว็บและไม่เห็นว่ามีการเปลี่ยนแปลงโค้ดของคุณเกิดขึ้น
เลเยอร์ใหม่
โดยปกติเมื่อสร้างเว็บไซต์ คุณมีเพียง 2 เลเยอร์ที่ต้องพิจารณา ได้แก่ ไคลเอ็นต์และเซิร์ฟเวอร์ Service Worker เป็นเลเยอร์ใหม่ที่ตั้งอยู่ตรงกลาง
ลองคิดว่าโปรแกรมทำงานของบริการเป็นเหมือนส่วนขยายเบราว์เซอร์ที่เว็บไซต์ของคุณติดตั้งในเบราว์เซอร์ของผู้ใช้ได้ เมื่อติดตั้งแล้ว โปรแกรมทำงานของบริการจะขยายเบราว์เซอร์สำหรับเว็บไซต์ของคุณด้วยเลเยอร์กลางที่มีประสิทธิภาพ เลเยอร์ Service Worker นี้สามารถสกัดกั้นและจัดการคำขอทั้งหมดที่เว็บไซต์ของคุณสร้างขึ้นได้
เลเยอร์ของ Service Worker มีวงจรของตัวเองโดยไม่ขึ้นอยู่กับแท็บเบราว์เซอร์ การรีเฟรชหน้าง่ายๆ ไม่เพียงพอที่จะอัปเดต Service Worker เหมือนที่คุณไม่น่าจะคาดหวังให้มีการรีเฟรชหน้าเพื่ออัปเดตโค้ดที่ทำให้ใช้งานได้ในเซิร์ฟเวอร์ แต่ละเลเยอร์มีกฎที่ไม่ซ้ำกันในการอัปเดต
ในเกม Service Workies เราครอบคลุมรายละเอียดมากมายของวงจรการทำงานของโปรแกรมทำงานของบริการ และให้คุณได้ฝึกทำงานกับโปรแกรมทำงานของบริการได้มากมาย
มีประสิทธิภาพ แต่มีข้อจำกัด
การมี Service Worker บนเว็บไซต์ของคุณจะให้ประโยชน์ที่น่าทึ่ง เว็บไซต์ของคุณสามารถทำสิ่งต่อไปนี้
- ทำงานได้อย่างราบรื่นแม้ว่าผู้ใช้ออฟไลน์อยู่
- ได้รับการปรับปรุงประสิทธิภาพครั้งใหญ่ผ่านการแคช
- ใช้ข้อความ Push
- ติดตั้งเป็น PWA
แม้ว่าโปรแกรมทำงานของบริการจะสามารถทำได้ แต่มีข้อจำกัดทางการออกแบบ ผู้ลงโฆษณาจะไม่สามารถดำเนินการใดๆ พร้อมกันหรือในชุดข้อความเดียวกันกับเว็บไซต์ของคุณ จึงทำให้ไม่สามารถเข้าถึงสิ่งต่อไปนี้ได้
- localStorage
- DOM
- หน้าต่าง
ข่าวดีคือมีวิธีสื่อสารกับ Service Worker ได้หลายวิธี ไม่ว่าจะเป็น postMessage
โดยตรง, ช่องทางส่งข้อความแบบหนึ่งต่อหนึ่ง และช่องออกอากาศ 1 ต่อหลายรายการ
อายุยาวนาน แต่อายุสั้น
โปรแกรมทำงานของบริการที่ใช้งานอยู่จะทำงานต่อไปแม้ว่าผู้ใช้จะออกจากเว็บไซต์หรือปิดแท็บไปแล้ว เบราว์เซอร์จะเก็บโปรแกรมทำงานของบริการนี้ไว้เพื่อให้พร้อมใช้งานเมื่อผู้ใช้กลับมาที่เว็บไซต์ของคุณในครั้งถัดไป โดยก่อนจะมีคำขอแรก โปรแกรมทำงานของบริการจะมีโอกาสสกัดกั้นและควบคุมหน้าเว็บได้ ซึ่งทำให้เว็บไซต์ทำงานแบบออฟไลน์ได้ โดยโปรแกรมทำงานของบริการสามารถแสดงหน้าเว็บเวอร์ชันที่แคชไว้ได้ แม้ว่าผู้ใช้จะไม่ได้เชื่อมต่ออินเทอร์เน็ตก็ตาม
ใน Service Workies เราแสดงภาพแนวคิดนี้กับ Kolohe (โปรแกรมทำงานของบริการที่เป็นมิตร) ในการสกัดกั้นและจัดการคำขอ
หยุดทำงานแล้ว
แม้ว่าโปรแกรมทำงานของบริการจะดูเหมือนว่าเป็นอมตะ แต่อาจถูกหยุดได้ทุกเมื่อ เบราว์เซอร์ไม่ต้องการสิ้นเปลืองทรัพยากรไปกับโปรแกรมทำงานของบริการที่ไม่ได้ทำอะไรในขณะนี้ การหยุดทำงานนั้นไม่เหมือนกับการถูกยุติ โดย Service Worker จะยังคงติดตั้งและเปิดใช้งานอยู่ แค่นี้ก็หลับได้แล้ว ครั้งถัดไปที่ต้องใช้ (เช่น ในการจัดการคำขอ) เบราว์เซอร์จะเรียกคืนการทำงาน
waitUntil
เนื่องจากมีความเป็นไปได้ที่จะเข้าสู่โหมดสลีปอยู่ตลอดเวลา โปรแกรมทำงานของบริการของคุณจึงต้องหาวิธีแจ้งให้เบราว์เซอร์ทราบเมื่อเบราว์เซอร์กำลังทำสิ่งที่สำคัญ และไม่รู้สึกอยากงีบหลับ นี่คือจุดที่ event.waitUntil()
จะเข้ามามีบทบาท วิธีนี้จะช่วยยืดวงจรการใช้งาน โดยป้องกันไม่ให้ระบบหยุดการทำงานและไปยังระยะถัดไปของวงจรจนกว่าเราจะพร้อม ซึ่งจะทำให้เรามีเวลาตั้งค่าแคช ดึงทรัพยากรจากเครือข่าย ฯลฯ
ตัวอย่างนี้บอกเบราว์เซอร์ว่า Service Worker ของเราไม่ได้ติดตั้งจนกว่าจะสร้างแคช assets
และสร้างรูปภาพรูปดาบขึ้นมา
self.addEventListener("install", event => {
event.waitUntil(
caches.open("assets").then(cache => {
return cache.addAll(["/weapons/sword/blade.png"]);
})
);
});
เฝ้าระวังสถานการณ์โลก
เมื่อเริ่มต้น/หยุดนี้ ขอบเขตรวมของโปรแกรมทำงานของบริการจะรีเซ็ต ดังนั้น โปรดระวังไม่ให้มีการใช้สถานะสากลใดๆ ในโปรแกรมทำงานของบริการ ไม่เช่นนั้นคุณจะรู้สึกเศร้าเมื่อกลับมาทำงานอีกครั้ง และมีสถานะแตกต่างจากที่คาดไว้
ลองดูตัวอย่างนี้ที่ใช้สถานะทั่วโลก
const favoriteNumber = Math.random();
let hasHandledARequest = false;
self.addEventListener("fetch", event => {
console.log(favoriteNumber);
console.log(hasHandledARequest);
hasHandledARequest = true;
});
ในคำขอแต่ละครั้ง Service Worker นี้จะบันทึกหมายเลข สมมติว่าเป็น 0.13981866382421893
ตัวแปร hasHandledARequest
จะเปลี่ยนเป็น true
ด้วย ขณะนี้โปรแกรมทำงานของบริการไม่มีการใช้งานไปสักระยะหนึ่ง เบราว์เซอร์จึงหยุดการทำงาน เมื่อมีคำขอเกิดขึ้นในครั้งหน้า จำเป็นต้องใช้โปรแกรมทำงานของบริการอีกครั้ง ดังนั้นเบราว์เซอร์จึงเริ่มต้นระบบ สคริปต์จะได้รับการประเมินอีกครั้ง ตอนนี้ hasHandledARequest
จะรีเซ็ตเป็น false
แล้ว และ favoriteNumber
นั้นต่างออกไปโดยสิ้นเชิง ซึ่งก็คือ 0.5907281835659033
คุณจะใช้สถานะที่จัดเก็บไว้ในโปรแกรมทำงานของบริการไม่ได้ นอกจากนี้ การสร้างอินสแตนซ์ของสิ่งต่างๆ เช่น ช่องทางข้อความอาจทำให้เกิดข้อบกพร่องได้ กล่าวคือคุณจะได้รับอินสแตนซ์ใหม่ทุกครั้งที่โปรแกรมทำงานของบริการหยุด/เริ่มทำงาน
ใน Service Workies บทที่ 3 เราแสดงภาพของ Service Worker ที่หยุดลงเป็นสีทั้งหมดในขณะที่รอให้เครื่องทำงาน
รวมกัน แต่แยกจากกัน
คุณจะควบคุมหน้าเว็บได้โดย Service Worker เพียงครั้งละ 1 รายเท่านั้น แต่สามารถติดตั้ง Service Worker ได้พร้อมกัน 2 โปรแกรม การแก้ไขรหัสโปรแกรมทำงานของบริการและรีเฟรชหน้าเว็บนั้น หมายความว่าคุณไม่ได้แก้ไขโปรแกรมทำงานของบริการอยู่เลย Service Worker จะเปลี่ยนแปลงไม่ได้ คุณกำลังสร้างใหม่แทน Service Worker ใหม่นี้ (ขอเรียกว่า SW2) จะติดตั้ง แต่ระบบยังไม่ได้เปิดใช้งาน จะต้องรอให้ Service Worker (SW1) ปัจจุบันสิ้นสุดการทำงาน (เมื่อผู้ใช้ออกจากเว็บไซต์)
การรับส่งข้อความกับแคชของโปรแกรมทำงานของบริการรายอื่น
ขณะติดตั้ง SW2 สามารถรับการตั้งค่าต่างๆ ได้ ซึ่งโดยปกติจะเป็นการสร้างและเก็บข้อมูลแคช แต่ขอแจ้งให้ทราบว่า Service Worker ใหม่นี้มีสิทธิ์เข้าถึงทุกอย่างที่ Service Worker ปัจจุบันมีสิทธิ์เข้าถึงได้ หากคุณไม่ระมัดระวัง โปรแกรมทำงานของบริการที่รอรับใหม่อาจสร้างปัญหาให้กับโปรแกรมทำงานของบริการปัจจุบันของคุณได้ ตัวอย่างที่อาจทำให้คุณพบปัญหามีดังนี้
- SW2 อาจลบแคชที่ SW1 ใช้อยู่
- SW2 อาจแก้ไขเนื้อหาของแคชที่ SW1 ใช้อยู่ ซึ่งทำให้ SW1 ตอบสนองด้วยเนื้อหาที่หน้าเว็บที่ไม่คาดคิด
ข้าม ข้าม รอ
โปรแกรมทำงานของบริการยังใช้เมธอด skipWaiting()
ที่มีความเสี่ยงเพื่อควบคุมหน้าทันทีที่ติดตั้งเสร็จได้ด้วย กรณีนี้ถือเป็นความคิดที่ไม่ดีนัก เว้นแต่คุณตั้งใจจะเปลี่ยน Service Worker ที่มีข้อบกพร่อง Service Worker ใหม่อาจใช้ทรัพยากรที่อัปเดตซึ่งหน้าปัจจุบันไม่ได้คาดหวัง ซึ่งนำไปสู่ข้อผิดพลาดและข้อบกพร่อง
เริ่มล้าง
วิธีป้องกันไม่ให้โปรแกรมทำงานของบริการ (Service Worker) ปิดบังซึ่งกันและกันคือตรวจสอบว่าโปรแกรมเหล่านั้นใช้แคชที่แตกต่างกัน วิธีที่ง่ายที่สุดในการดำเนินการดังกล่าวคือการกำหนดเวอร์ชันชื่อแคชที่ใช้
const version = 1;
const assetCacheName = `assets-${version}`;
self.addEventListener("install", event => {
caches.open(assetCacheName).then(cache => {
// confidently do stuff with your very own cache
});
});
เมื่อทำให้ Service Worker ใหม่ใช้งานได้ คุณจะสลับ version
เพื่อให้ทำงานที่ต้องการด้วยแคชที่แยกต่างหากจากโปรแกรมทำงานของบริการก่อนหน้า
สิ้นสุดการล้าง
เมื่อ Service Worker ทำงานถึงสถานะ activated
คุณจะทราบว่าได้เข้ามาแทนที่แล้ว และ Service Worker เดิมจะทำงานซ้ำซ้อน ณ จุดนี้ เป็นเรื่องสำคัญที่จะต้องล้างข้อมูลหลังจาก Service Worker เก่า วิธีนี้ไม่เพียงเคารพผู้ใช้ ขีดจำกัดพื้นที่เก็บข้อมูลแคช แต่ก็สามารถป้องกันข้อบกพร่องที่ไม่ได้ตั้งใจได้ด้วย
เมธอด caches.match()
เป็นแป้นพิมพ์ลัดที่มักใช้ในการเรียกข้อมูลรายการจากแคชใดก็ได้ที่มีข้อมูลตรงกัน แต่จะทำซ้ำผ่านแคชตามลำดับที่สร้างขึ้น สมมติว่าคุณมีไฟล์สคริปต์ 2 เวอร์ชัน app.js
ในแคช 2 รายการ คือ assets-1
และ assets-2
หน้าเว็บของคุณต้องการสคริปต์ที่ใหม่กว่าซึ่งจัดเก็บไว้ใน assets-2
แต่หากคุณยังไม่ได้ลบแคชเก่า caches.match('app.js')
จะคืนค่าเวอร์ชันเก่าจาก assets-1
และอาจทำให้เว็บไซต์เสียหาย
เพียงแค่ลบแคชที่ Service Worker ใหม่ไม่ต้องใช้
const version = 2;
const assetCacheName = `assets-${version}`;
self.addEventListener("activate", event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheName !== assetCacheName){
return caches.delete(cacheName);
}
});
);
});
);
});
การป้องกันไม่ให้ผู้ปฏิบัติงานบริการของคุณในเว็บซ้ำใครกันนั้นต้องใช้ทั้งการทำงานและระเบียบวินัย แต่ก็คุ้มค่ากับปัญหา
แนวความคิดของ Service Worker
การกำหนดแนวคิดที่เหมาะสมและนึกถึงโปรแกรมทำงานของบริการจะช่วยให้คุณสร้างแนวคิดของตนเองได้อย่างมั่นใจ เมื่อได้ใช้งานแล้ว คุณจะสร้างประสบการณ์การใช้งานที่น่าทึ่งให้กับผู้ใช้ได้
หากคุณต้องการทำความเข้าใจข้อมูลทั้งหมดนี้ด้วยการเล่นเกม ถือว่าโชคดีแล้ว! ไปเล่นเกม Service Workies ที่คุณจะได้เรียนรู้วิธีทำงานของบริการทำงานด้านสัตว์เพื่อฆ่าสัตว์ที่ออฟไลน์