โปรแกรมทำงานของบริการที่ใหม่กว่าโดยค่าเริ่มต้น

เจฟฟ์ พอสนิก
เจฟฟ์ พอสนิก

tl;dr

ตั้งแต่ Chrome 68 เป็นต้นไป คำขอ HTTP ที่ตรวจหาอัปเดตสคริปต์ Service Worker จะไม่ถูกดำเนินการด้วยแคช HTTP อีกต่อไปโดยค่าเริ่มต้น วิธีนี้ช่วยแก้ปัญหาปัญหาทั่วไปของนักพัฒนาซอฟต์แวร์ ซึ่งการตั้งค่าส่วนหัว Cache-Control โดยไม่ตั้งใจในสคริปต์โปรแกรมทำงานของบริการอาจทำให้การอัปเดตล่าช้า

หากคุณเลือกไม่ใช้การแคช HTTP สำหรับสคริปต์ /service-worker.js โดยแสดงสคริปต์ด้วย Cache-Control: max-age=0 แล้ว คุณไม่น่าจะเห็นการเปลี่ยนแปลงเนื่องจากลักษณะการทำงานเริ่มต้นแบบใหม่

นอกจากนี้ ตั้งแต่ Chrome 78 เป็นต้นไป ระบบจะใช้การเปรียบเทียบแบบไบต์ต่อไบต์กับสคริปต์ที่โหลดใน Service Worker ผ่าน importScripts() การเปลี่ยนแปลงสคริปต์ที่นำเข้าจะทริกเกอร์ขั้นตอนการอัปเดตโปรแกรมทำงานของบริการ เช่นเดียวกับการเปลี่ยนแปลงโปรแกรมทำงานของบริการระดับบนสุด

ที่มา

ทุกครั้งที่คุณไปยังหน้าใหม่ที่อยู่ในขอบเขตของ Service Worker ให้เรียกใช้ registration.update() จาก JavaScript อย่างชัดแจ้ง หรือเมื่อ Service Worker "ตื่น" ผ่านเหตุการณ์ push หรือ sync เบราว์เซอร์จะขอทรัพยากร JavaScript ที่ส่งไปยังการเรียก navigator.serviceWorker.register() ก่อนหน้านี้เพื่อค้นหาอัปเดตสคริปต์โปรแกรมทำงานของบริการไปด้วย

สำหรับบทความนี้ สมมติว่า URL ของบทความคือ /service-worker.js และมีการเรียก importScripts() ครั้งเดียว ซึ่งจะโหลดโค้ดเพิ่มเติมที่ทำงานภายใน Service Worker

// Inside our /service-worker.js file:
importScripts('path/to/import.js');

// Other top-level code goes here.

สิ่งที่เปลี่ยนแปลงไป

ก่อน Chrome 68 คำขออัปเดตสำหรับ /service-worker.js จะดำเนินการผ่านแคช HTTP (เนื่องจากมีการดึงข้อมูลส่วนใหญ่) ซึ่งหมายความว่าหากส่งสคริปต์ด้วย Cache-Control: max-age=600 ในตอนแรก การอัปเดตภายใน 600 วินาที (10 นาที) จะไม่ไปยังเครือข่าย ดังนั้นผู้ใช้อาจไม่ได้รับ Service Worker เวอร์ชันล่าสุด แต่หาก max-age มากกว่า 86400 (24 ชั่วโมง) ระบบจะปฏิบัติเสมือนเป็น 86400 เพื่อป้องกันไม่ให้ผู้ใช้ติดอยู่กับเวอร์ชันใดเวอร์ชันหนึ่งตลอดไป

ตั้งแต่ปี 68 เป็นต้นไป ระบบจะไม่สนใจแคช HTTP เมื่อขออัปเดตสคริปต์ Service Worker ดังนั้นเว็บแอปพลิเคชันที่มีอยู่จึงอาจเห็นความถี่ของคำขอสำหรับสคริปต์ Service Worker เพิ่มขึ้น คำขอสำหรับ importScripts จะยังคงส่งผ่านแคช HTTP แต่นี่เป็นเพียงตัวเลือกเริ่มต้น ซึ่งก็คือตัวเลือกการจดทะเบียนใหม่ updateViaCache ที่พร้อมใช้งานซึ่งให้คุณควบคุมลักษณะการทำงานนี้ได้

updateViaCache

ตอนนี้นักพัฒนาซอฟต์แวร์จะส่งตัวเลือกใหม่เมื่อเรียกใช้ navigator.serviceWorker.register() ได้ นั่นคือพารามิเตอร์ updateViaCache โดยจะใช้ 1 ใน 3 ค่า ได้แก่ 'imports', 'all' หรือ 'none'

ค่าดังกล่าวจะกำหนดว่าแคช HTTP มาตรฐานของเบราว์เซอร์จะเข้ามามีบทบาทหรือไม่และจะมีผลอย่างไรเมื่อส่งคำขอ HTTP เพื่อตรวจสอบทรัพยากรของ Service Worker ที่อัปเดต

  • เมื่อตั้งค่าเป็น 'imports' ระบบจะไม่ปรึกษาแคช HTTP เมื่อตรวจหาการอัปเดตสคริปต์ /service-worker.js แต่ระบบจะปรึกษาเมื่อดึงข้อมูลสคริปต์ที่นำเข้า (เช่น path/to/import.js) ซึ่งเป็นค่าเริ่มต้นและตรงกับลักษณะการทํางานเริ่มต้นใน Chrome 68

  • เมื่อตั้งค่าเป็น 'all' ระบบจะพิจารณาแคช HTTP เมื่อส่งคำขอสำหรับสคริปต์ /service-worker.js ระดับบนสุด รวมถึงสคริปต์ที่นำเข้าภายในโปรแกรมทำงานของบริการ เช่น path/to/import.js ตัวเลือกนี้สอดคล้องกับลักษณะการทำงานก่อนหน้าใน Chrome ก่อนหน้า Chrome 68

  • เมื่อตั้งค่าเป็น 'none' ระบบจะไม่พิจารณาแคช HTTP เมื่อส่งคำขอสำหรับ /service-worker.js ระดับบนสุดหรือสคริปต์ที่นำเข้า เช่น path/to/import.js สมมติ

เช่น โค้ดต่อไปนี้จะลงทะเบียน Service Worker และตรวจสอบว่าไม่มีการปรึกษาแคช HTTP เมื่อตรวจหาการอัปเดตสคริปต์ /service-worker.js หรือสำหรับสคริปต์ที่อ้างอิงผ่าน importScripts() ภายใน /service-worker.js

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js', {
    updateViaCache: 'none',
    // Optionally, set 'scope' here, if needed.
  });
}

ตรวจหาการอัปเดตสคริปต์ที่นำเข้า

ก่อน Chrome 78 ระบบจะเรียกสคริปต์ของ Service Worker ที่โหลดผ่าน importScripts() เพียงครั้งเดียว (ตรวจสอบกับแคช HTTP ก่อน หรือผ่านเครือข่าย โดยขึ้นอยู่กับการกำหนดค่า updateViaCache) หลังจากการดึงข้อมูลครั้งแรก เบราว์เซอร์จะจัดเก็บไว้ในภายในและไม่เรียกข้อมูลอีก

วิธีเดียวที่จะบังคับให้โปรแกรมทำงานของบริการที่ติดตั้งไว้แล้วยอมรับการเปลี่ยนแปลงของสคริปต์ที่นำเข้าคือการเปลี่ยน URL ของสคริปต์ ซึ่งโดยปกติจะเป็นการเพิ่มค่าเซมเวอร์ (เช่น importScripts('https://example.com/v1.1.0/index.js')) หรือใส่แฮชของเนื้อหา (เช่น importScripts('https://example.com/index.abcd1234.js')) ผลข้างเคียงจากการเปลี่ยน URL ที่นำเข้าคือการเปลี่ยนแปลงเนื้อหาของสคริปต์บริการระดับบนสุด ซึ่งจะทำให้ขั้นตอนการอัปเดตในโปรแกรมทำงานของบริการระดับบนสุดจะทริกเกอร์ขั้นตอนการอัปเดต

ตั้งแต่ Chrome 78 เป็นต้นไป ทุกครั้งที่มีการตรวจสอบการอัปเดตสำหรับไฟล์โปรแกรมทำงานของบริการระดับบนสุด ระบบจะตรวจสอบในเวลาเดียวกันเพื่อพิจารณาว่าเนื้อหาของสคริปต์ที่นำเข้ามีการเปลี่ยนแปลงหรือไม่ แคช HTTP อาจดำเนินการตามส่วนหัว Cache-Control ที่ใช้ หากตั้งค่า updateViaCache เป็น 'all' หรือ 'imports' (ซึ่งเป็นค่าเริ่มต้น) หรือการตรวจสอบอาจดำเนินการกับเครือข่ายโดยตรงหากตั้งค่า updateViaCache เป็น 'none' ทั้งนี้ขึ้นอยู่กับส่วนหัว Cache-Control ที่ใช้

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

ลักษณะการทำงานของ Chrome 78 ตรงกับสิ่งที่ Firefox นำมาใช้ เมื่อหลายปีก่อนใน Firefox 56 ซึ่ง Safari ก็นำลักษณะการทำงานนี้ ไปใช้อยู่แล้วเช่นกัน

นักพัฒนาแอปต้องทำอะไรบ้าง

หากคุณเลือกไม่ใช้การแคช HTTP สำหรับสคริปต์ /service-worker.js อย่างมีประสิทธิภาพโดยแสดงสคริปต์ด้วย Cache-Control: max-age=0 (หรือค่าที่คล้ายกัน) คุณก็ไม่ควรจะเห็นการเปลี่ยนแปลงใดๆ เนื่องจากลักษณะการทำงานเริ่มต้นใหม่

หากคุณแสดงสคริปต์ /service-worker.js โดยเปิดใช้การแคช HTTP ไม่ว่าจะตั้งใจหรือเพราะเป็นเพียงค่าเริ่มต้นสำหรับสภาพแวดล้อมโฮสติ้ง คุณอาจเริ่มเห็นคำขอ HTTP เพิ่มเติมสำหรับ /service-worker.js ที่สร้างขึ้นไปยังเซิร์ฟเวอร์ของคุณมีจำนวนเพิ่มขึ้น คำขอเหล่านี้คือคำขอที่ใช้แคช HTTP ดำเนินการ หากต้องการอนุญาตให้ค่าส่วนหัว Cache-Control ส่งผลต่อความใหม่ของ /service-worker.js ต่อไป คุณจะต้องเริ่มการตั้งค่า updateViaCache: 'all' อย่างชัดเจนเมื่อลงทะเบียน Service Worker

เนื่องจากเบราว์เซอร์เวอร์ชันเก่าอาจมีกลุ่มผู้ใช้จำนวนมาก คุณจึงควรตั้งค่าส่วนหัว HTTP ของ Cache-Control: max-age=0 ในสคริปต์โปรแกรมทำงานของบริการต่อไป แม้ว่าเบราว์เซอร์รุ่นใหม่ๆ อาจไม่สนใจก็ตาม

นักพัฒนาซอฟต์แวร์สามารถใช้โอกาสนี้ตัดสินใจว่าต้องการเลือกไม่ใช้การแคช HTTP สำหรับสคริปต์ที่นำเข้าอย่างชัดแจ้งในตอนนี้หรือไม่ และเพิ่ม updateViaCache: 'none' ลงในการลงทะเบียน Service Worker ของตนตามความเหมาะสม

การแสดงสคริปต์ที่นำเข้า

ตั้งแต่ Chrome 78 เป็นต้นไป นักพัฒนาซอฟต์แวร์อาจเห็นคำขอ HTTP ขาเข้าสำหรับทรัพยากรที่โหลดผ่าน importScripts() มากขึ้น เนื่องจากตอนนี้จะมีการตรวจหาอัปเดต

หากต้องการหลีกเลี่ยงการเข้าชมผ่าน HTTP เพิ่มเติมนี้ ให้ตั้งค่าส่วนหัว Cache-Control ที่มีอายุการใช้งานยาวนานเมื่อแสดงสคริปต์ที่มีเซมเวอร์หรือแฮชใน URL และอาศัยลักษณะการทํางาน updateViaCache เริ่มต้นของ 'imports'

หรือหากต้องการต้องการตรวจสอบสคริปต์ที่นำเข้าเพื่อรับการอัปเดตเป็นประจำ ให้ตรวจสอบว่าแสดงสคริปต์ด้วย Cache-Control: max-age=0 หรือคุณใช้ updateViaCache: 'none'

อ่านเพิ่มเติม

"วงจรการทำงานของ Service Worker" และ "แนวทางปฏิบัติแนะนำในการแคชและ Getchas อายุสูงสุด" ซึ่งทั้ง 2 อย่างโดย Jake Archibald แนะนำให้อ่านสำหรับนักพัฒนาซอฟต์แวร์ทุกคนที่ติดตั้งใช้งานทุกอย่างบนเว็บ