การสนับสนุนเบราว์เซอร์
- 68
- 79
- x
- x
เบราว์เซอร์ที่ทันสมัยในปัจจุบันจะระงับหน้าเว็บหรือทิ้งหน้าเว็บไปเลยเมื่อทรัพยากรของระบบถูกจำกัด ในอนาคต เบราว์เซอร์ต้องการดำเนินการนี้ในเชิงรุก เพื่อให้ใช้พลังงานและหน่วยความจำน้อยลง Page Lifecycle API มีฮุกสำหรับวงจร ดังนั้นหน้าเว็บจึงจัดการกับการแทรกแซงเบราว์เซอร์เหล่านี้ได้อย่างปลอดภัยโดยไม่ส่งผลกระทบต่อประสบการณ์ของผู้ใช้ ลองดูที่ API เพื่อดูว่าคุณควรนำฟีเจอร์เหล่านี้ไปใช้กับแอปพลิเคชันหรือไม่
ที่มา
วงจรของแอปพลิเคชันเป็นวิธีหลักที่ระบบปฏิบัติการสมัยใหม่ใช้จัดการทรัพยากร ใน Android, iOS และ Windows เวอร์ชันล่าสุด ระบบปฏิบัติการสามารถเริ่มและหยุดแอปได้ทุกเมื่อ วิธีนี้จะช่วยให้แพลตฟอร์มเหล่านี้เพิ่มประสิทธิภาพและจัดสรรทรัพยากรในจุดที่สร้างประโยชน์สูงสุดให้แก่ผู้ใช้ได้
ที่ผ่านมา ในเว็บไม่มีวงจรเช่นนี้ และแอปต่างๆ สามารถอยู่ได้ตลอดไป เนื่องจากหน้าเว็บจำนวนมากกำลังทำงานอยู่ ทรัพยากรระบบที่สำคัญ เช่น หน่วยความจำ, CPU, แบตเตอรี่ และเครือข่าย อาจมีการสมัครมากเกินไป ซึ่งส่งผลให้ผู้ใช้ปลายทางได้รับประสบการณ์ที่ไม่ดี
แม้ว่าแพลตฟอร์มเว็บมีเหตุการณ์ที่เกี่ยวข้องกับสถานะของวงจรมานานแล้ว เช่น load
, unload
และ visibilitychange
แต่เหตุการณ์เหล่านี้อนุญาตให้นักพัฒนาแอปตอบสนองต่อการเปลี่ยนแปลงสถานะที่เริ่มต้นโดยผู้ใช้เท่านั้น เบราว์เซอร์จำเป็นต้องมีวิธีในการกู้คืนและจัดสรรทรัพยากรของระบบใหม่อีกครั้งเพื่อให้เว็บทำงานได้อย่างเสถียรบนอุปกรณ์ที่ใช้พลังงานต่ำ (และให้ความสำคัญกับทรัพยากรโดยทั่วไปในทุกแพลตฟอร์ม)
อันที่จริงแล้ว เบราว์เซอร์ในปัจจุบันใช้มาตรการต่างๆ เพื่ออนุรักษ์ทรัพยากรสำหรับหน้าเว็บในแท็บเบื้องหลังอยู่แล้ว และเบราว์เซอร์จำนวนมาก (โดยเฉพาะ Chrome) ก็ต้องการทำมากกว่านี้ เพื่อลดการใช้ทรัพยากรโดยรวม
ปัญหาคือ นักพัฒนาซอฟต์แวร์ไม่มีวิธีเตรียมตัวสำหรับการแทรกแซงที่เริ่มต้นโดยระบบเหล่านี้ หรือแม้กระทั่งรู้ว่ากำลังเกิดขึ้น ซึ่งหมายความว่าเบราว์เซอร์ต่างๆ จะต้องเข้มงวดหรือมีความเสี่ยงที่จะทำลายหน้าเว็บ
Page Lifecycle API จะพยายามแก้ไขปัญหานี้ดังนี้
- ขอแนะนำและกำหนดมาตรฐานให้กับแนวคิดเกี่ยวกับสถานะวงจรบนเว็บ
- การกำหนดสถานะใหม่ที่เริ่มต้นโดยระบบซึ่งอนุญาตให้เบราว์เซอร์จำกัดทรัพยากรที่แท็บซ่อนหรือแท็บไม่ได้ใช้งานสามารถใช้ได้
- การสร้าง API และเหตุการณ์ใหม่ที่ช่วยให้นักพัฒนาเว็บตอบสนองต่อการเปลี่ยนผ่านไปยังและจากสถานะที่เริ่มต้นโดยระบบใหม่เหล่านี้ได้
โซลูชันนี้ช่วยให้นักพัฒนาเว็บที่คาดเดาได้ต้องสร้างแอปพลิเคชันที่ยืดหยุ่นสำหรับการแทรกแซงระบบ และช่วยให้เบราว์เซอร์เพิ่มประสิทธิภาพทรัพยากรของระบบได้มากขึ้น ซึ่งสุดท้ายแล้วเป็นประโยชน์ต่อผู้ใช้เว็บทุกคน
เนื้อหาที่เหลือของโพสต์นี้จะแนะนำฟีเจอร์วงจรของหน้าเว็บใหม่ และดูว่าฟีเจอร์ดังกล่าวเกี่ยวข้องกับสถานะและเหตุการณ์ของแพลตฟอร์มเว็บที่มีอยู่ทั้งหมดอย่างไร นอกจากนี้ยังให้คำแนะนำและแนวทางปฏิบัติแนะนำเกี่ยวกับประเภทงานที่นักพัฒนาแอปควร (และไม่ควร) ทำในแต่ละรัฐด้วย
ภาพรวมสถานะและเหตุการณ์ในวงจรของหน้า
สถานะวงจรของหน้าทั้งหมดจะแยกกันและแยกออกจากกัน ซึ่งหมายความว่าหน้าเว็บจะอยู่ในสถานะได้ทีละ 1 สถานะเท่านั้น และโดยทั่วไป การเปลี่ยนแปลงส่วนใหญ่ต่อสถานะวงจรของหน้าจะสังเกตได้ผ่านทางเหตุการณ์ DOM (ดูข้อยกเว้นในคำแนะนำสำหรับนักพัฒนาซอฟต์แวร์สำหรับแต่ละสถานะ)
วิธีที่ง่ายที่สุดในการอธิบายสถานะของวงจรของหน้าเว็บ รวมถึงเหตุการณ์ที่ส่งสัญญาณการเปลี่ยนระหว่างสถานะเหล่านี้คือการใช้แผนภาพ
รัฐ
ตารางต่อไปนี้จะอธิบายรายละเอียดของแต่ละสถานะ นอกจากนี้ยังระบุสถานะที่เป็นไปได้ที่อาจเกิดขึ้นทั้งก่อนและหลัง รวมถึงเหตุการณ์ที่นักพัฒนาซอฟต์แวร์สามารถใช้เพื่อสังเกตการเปลี่ยนแปลงได้
รัฐ | คำอธิบาย |
---|---|
ใช้งานอยู่ |
หน้าจะอยู่ในสถานะใช้งาน หากมองเห็นได้และมีโฟกัสอินพุต
สถานะก่อนหน้าที่เป็นไปได้มีดังนี้ |
เชิงรับ |
หน้าจะอยู่ในสถานะพาสซีฟ หากมองเห็นได้และไม่ได้โฟกัสอินพุต
สถานะก่อนหน้าที่เป็นไปได้:
สถานะถัดไปที่เป็นไปได้: |
ซ่อนอยู่ |
หน้าเว็บจะอยู่ในสถานะซ่อนอยู่หากมองไม่เห็น (และไม่ถูกตรึง ทิ้ง หรือสิ้นสุด)
สถานะก่อนหน้าที่เป็นไปได้:
สถานะถัดไปที่เป็นไปได้: |
หยุดการทำงาน |
ในสถานะค้าง เบราว์เซอร์จะระงับการดำเนินการของ
freezable
งานใน
คิวงานของหน้าเว็บจนกว่าหน้าเว็บจะไม่ค้าง ซึ่งหมายความว่าสิ่งต่างๆ เช่น ตัวจับเวลา JavaScript และโค้ดเรียกกลับการดึงข้อมูลจะไม่ทำงาน งานที่ทำงานอยู่แล้วอาจเสร็จสิ้นได้ (ที่สำคัญที่สุดคือโค้ดเรียกกลับของ
เบราว์เซอร์จะตรึงหน้าเว็บเพื่อประหยัดการใช้ CPU/แบตเตอรี่/ข้อมูล และยังช่วยให้ การนำทางย้อนกลับ/ไปข้างหน้าทำงานได้เร็วขึ้น ทำให้ไม่ต้องโหลดหน้าเว็บซ้ำแบบเต็มหน้า
สถานะก่อนหน้าที่เป็นไปได้:
สถานะถัดไปที่เป็นไปได้: |
ยกเลิกแล้ว |
หน้าเว็บจะอยู่ในสถานะสิ้นสุดการใช้งานหลังจากที่เบราว์เซอร์เริ่มยกเลิกการโหลดและล้างออกจากหน่วยความจำ ไม่มี งานใหม่ที่เริ่มต้นได้ในสถานะนี้ และงานที่อยู่ระหว่างดำเนินการอาจถูกยุติหากทำงานนานเกินไป
สถานะก่อนหน้าที่เป็นไปได้:
สถานะถัดไปที่เป็นไปได้: |
ทิ้งแล้ว |
หน้าจะอยู่ในสถานะถูกยกเลิกเมื่อเบราว์เซอร์ยกเลิกการโหลดเพื่อประหยัดทรัพยากร จะไม่มีงาน โค้ดเรียกกลับของเหตุการณ์ หรือ JavaScript ประเภทใดก็ตามที่ทำงานในสถานะนี้ได้ เนื่องจากโดยปกติการทิ้งจะเกิดขึ้นภายใต้ข้อจำกัดทรัพยากร ซึ่งเริ่มต้นกระบวนการใหม่ไม่ได้ ในกรณีที่ยกเลิกแล้ว ผู้ใช้มักเห็นแท็บนั้น (รวมถึงชื่อแท็บและไอคอน Fav) แม้ว่าหน้าจะหายไปก็ตาม
สถานะก่อนหน้าที่เป็นไปได้:
สถานะถัดไปที่เป็นไปได้: |
กิจกรรม
เบราว์เซอร์ส่งเหตุการณ์จำนวนมาก แต่มีเพียงส่วนน้อยเท่านั้นที่เป็นสัญญาณว่าสถานะวงจรของหน้ามีการเปลี่ยนแปลงที่เป็นไปได้ ตารางต่อไปนี้จะสรุปเหตุการณ์ทั้งหมดที่เกี่ยวข้องกับวงจรชีวิต และแสดงรายการสถานะที่เหตุการณ์เหล่านี้อาจเปลี่ยนแปลง
ชื่อ | รายละเอียด |
---|---|
focus
|
องค์ประกอบ DOM ได้รับการโฟกัส
หมายเหตุ: เหตุการณ์
สถานะก่อนหน้าที่เป็นไปได้:
สถานะปัจจุบันที่เป็นไปได้: |
blur
|
องค์ประกอบ DOM หายไปโฟกัส
หมายเหตุ: เหตุการณ์
สถานะก่อนหน้าที่เป็นไปได้:
สถานะปัจจุบันที่เป็นไปได้: |
visibilitychange
|
มีการเปลี่ยนแปลงค่า
สถานะก่อนหน้าที่เป็นไปได้: |
freeze
*
|
หน้าเว็บหยุดทำงานชั่วคราว งานที่ ตรึงได้ในคิวงานของหน้าเว็บจะไม่เริ่มต้น
สถานะก่อนหน้าที่เป็นไปได้:
สถานะปัจจุบันที่เป็นไปได้: |
resume
*
|
เบราว์เซอร์ได้กลับสู่หน้าที่ค้างอีกครั้ง
สถานะก่อนหน้าที่เป็นไปได้:
สถานะปัจจุบันที่เป็นไปได้: |
pageshow
|
ระบบกำลังข้ามการส่งรายการประวัติเซสชัน ซึ่งอาจเป็นการโหลดหน้าเว็บใหม่หรือหน้าเว็บที่มาจากแคชย้อนหลัง หากหน้ามาจาก Back-Forward Cache พร็อพเพอร์ตี้
สถานะก่อนหน้าที่เป็นไปได้:
สถานะปัจจุบันที่เป็นไปได้: |
pagehide
|
ระบบกำลังข้ามรายการประวัติเซสชัน หากผู้ใช้ไปยังหน้าอื่นและเบราว์เซอร์สามารถเพิ่มหน้าปัจจุบันลงใน Back/Forward Cache เพื่อนำกลับมาใช้ใหม่ได้ในภายหลัง พร็อพเพอร์ตี้
สถานะก่อนหน้าที่เป็นไปได้:
สถานะปัจจุบันที่เป็นไปได้: |
beforeunload
|
ระบบกำลังจะยกเลิกการโหลดหน้าต่าง เอกสาร และทรัพยากรของเอกสาร เอกสารจะยังคงปรากฏให้เห็นและยังคงยกเลิกกิจกรรมได้ในจุดนี้
สำคัญ: ควรใช้เหตุการณ์
สถานะก่อนหน้าที่เป็นไปได้:
สถานะปัจจุบันที่เป็นไปได้: |
unload
|
ระบบกำลังยกเลิกการโหลดหน้านี้
คำเตือน: ไม่แนะนำให้ใช้เหตุการณ์
สถานะก่อนหน้าที่เป็นไปได้:
สถานะปัจจุบันที่เป็นไปได้: |
* ระบุเหตุการณ์ใหม่ที่กำหนดโดย Page Lifecycle API
เพิ่มฟีเจอร์ใหม่ใน Chrome 68 แล้ว
แผนภูมิก่อนหน้าแสดง 2 สถานะที่เริ่มต้นโดยระบบแทนที่จะเป็นเริ่มต้นโดยผู้ใช้ ได้แก่ ค้างและยกเลิก ดังที่กล่าวไว้ก่อนหน้านี้ ปัจจุบันเบราว์เซอร์จะระงับและทิ้งแท็บที่ซ่อนอยู่เป็นครั้งคราว (ตามการพิจารณาตามที่เห็นสมควร) แต่นักพัฒนาซอฟต์แวร์ไม่สามารถทราบได้เมื่อมีการดำเนินการดังกล่าว
ตอนนี้นักพัฒนาแอปใน Chrome 68 จะสังเกตได้ว่าแท็บที่ซ่อนอยู่ถูกตรึงและค้างโดยรอฟังเหตุการณ์ freeze
และ resume
ในวันที่ document
document.addEventListener('freeze', (event) => {
// The page is now frozen.
});
document.addEventListener('resume', (event) => {
// The page has been unfrozen.
});
ตั้งแต่ Chrome 68 เป็นต้นไป ออบเจ็กต์ document
จะมีพร็อพเพอร์ตี้ wasDiscarded
ใน Chrome บนเดสก์ท็อป (กําลังติดตามการสนับสนุนของ Android ในปัญหานี้) หากต้องการตรวจสอบว่าหน้าเว็บถูกทิ้งขณะอยู่ในแท็บที่ซ่อนอยู่หรือไม่ คุณสามารถตรวจสอบค่าของพร็อพเพอร์ตี้นี้เมื่อโหลดหน้าเว็บ (หมายเหตุ: ต้องโหลดหน้าเว็บที่เลิกใช้งานแล้วซ้ำเพื่อใช้อีกครั้ง)
if (document.wasDiscarded) {
// Page was previously discarded by the browser while in a hidden tab.
}
โปรดดูคําแนะนําสําหรับนักพัฒนาซอฟต์แวร์ในแต่ละรัฐ เพื่อดูคำแนะนำเกี่ยวกับสิ่งสำคัญที่ต้องทำในกิจกรรม freeze
และ resume
รวมถึงวิธีจัดการและเตรียมพร้อมสําหรับหน้าที่ถูกทิ้ง
หลายส่วนถัดจากนี้จะอธิบายภาพรวมว่าฟีเจอร์ใหม่เหล่านี้เหมาะกับสถานะและกิจกรรมของแพลตฟอร์มเว็บที่มีอยู่อย่างไร
วิธีสังเกตสถานะของวงจรหน้าเว็บในโค้ด
ในสถานะแอ็กทีฟ พาสซีฟ และซ่อน คุณสามารถเรียกใช้โค้ด JavaScript ที่จะระบุสถานะวงจรการใช้งานหน้าเว็บปัจจุบันจาก API แพลตฟอร์มเว็บที่มีอยู่
const getState = () => {
if (document.visibilityState === 'hidden') {
return 'hidden';
}
if (document.hasFocus()) {
return 'active';
}
return 'passive';
};
ในทางกลับกัน สถานะค้างและสิ้นสุดจะตรวจพบได้ใน Listener เหตุการณ์ที่เกี่ยวข้องเท่านั้น (freeze
และ pagehide
) ในขณะที่สถานะมีการเปลี่ยนแปลง
วิธีสังเกตการเปลี่ยนแปลงสถานะ
การสร้างบนฟังก์ชัน getState()
ที่กําหนดไว้ก่อนหน้านี้ คุณสามารถดูการเปลี่ยนแปลงสถานะวงจรทั้งหมดของหน้าเว็บได้ด้วยโค้ดต่อไปนี้
// Stores the initial state using the `getState()` function (defined above).
let state = getState();
// Accepts a next state and, if there's been a state change, logs the
// change to the console. It also updates the `state` value defined above.
const logStateChange = (nextState) => {
const prevState = state;
if (nextState !== prevState) {
console.log(`State change: ${prevState} >>> ${nextState}`);
state = nextState;
}
};
// Options used for all event listeners.
const opts = {capture: true};
// These lifecycle events can all use the same listener to observe state
// changes (they call the `getState()` function to determine the next state).
['pageshow', 'focus', 'blur', 'visibilitychange', 'resume'].forEach((type) => {
window.addEventListener(type, () => logStateChange(getState(), opts));
});
// The next two listeners, on the other hand, can determine the next
// state from the event itself.
window.addEventListener('freeze', () => {
// In the freeze event, the next state is always frozen.
logStateChange('frozen');
}, opts);
window.addEventListener('pagehide', (event) => {
// If the event's persisted property is `true` the page is about
// to enter the back/forward cache, which is also in the frozen state.
// If the event's persisted property is not `true` the page is
// about to be unloaded.
logStateChange(event.persisted ? 'frozen' : 'terminated');
}, opts);
โค้ดนี้มี 3 สิ่งต่อไปนี้
- ตั้งสถานะเริ่มต้นโดยใช้ฟังก์ชัน
getState()
- กำหนดฟังก์ชันที่ยอมรับสถานะถัดไป และหากมีการเปลี่ยนแปลง ระบบจะบันทึกการเปลี่ยนแปลงสถานะไปยังคอนโซล
- เพิ่ม
การบันทึก
Listener เหตุการณ์สำหรับเหตุการณ์ในวงจรทั้งหมดที่จำเป็น ซึ่งส่งผลให้เป็นการเรียกใช้
logStateChange()
ผ่านในสถานะถัดไป
สิ่งหนึ่งที่ควรทราบเกี่ยวกับโค้ดคือระบบจะเพิ่ม Listener เหตุการณ์ทั้งหมดลงใน window
และทั้งหมดจะผ่าน {capture: true}
ซึ่งอาจเป็นเพราะสาเหตุต่อไปนี้
- เหตุการณ์ในวงจรหน้าเว็บบางเหตุการณ์ไม่ได้มีเป้าหมายเหมือนกัน
pagehide
และpageshow
เริ่มทำงานเมื่อwindow
,visibilitychange
,freeze
และresume
เริ่มทำงานในdocument
รวมทั้งfocus
และblur
เริ่มทำงานในองค์ประกอบ DOM ที่เกี่ยวข้อง - เหตุการณ์เหล่านี้ส่วนใหญ่จะไม่แสดงเป็นลูกโป่ง ซึ่งหมายความว่าคุณจะเพิ่ม Listener เหตุการณ์ที่ไม่บันทึกไปยังองค์ประกอบระดับบนทั่วไปและสังเกตการณ์ทั้งหมดไม่ได้
- เฟสการบันทึกจะทำงานก่อนเฟสเป้าหมายหรือบับเบิล ดังนั้นการเพิ่มผู้ฟังในจุดดังกล่าวจึงช่วยให้มั่นใจได้ว่าโค้ดจะทำงานก่อนที่โค้ดอื่นๆ จะยกเลิกได้
คำแนะนำจากนักพัฒนาแอปสำหรับแต่ละรัฐ
ในฐานะนักพัฒนาแอป คุณควรเข้าใจสถานะของวงจรการใช้งานหน้าเว็บและรู้วิธีสังเกตสถานะเหล่านี้ในโค้ด เนื่องจากประเภทงานที่คุณควร (และไม่ควร) ทำนั้นจะขึ้นอยู่กับสถานะของหน้าเว็บเป็นหลัก
เช่น การแสดงการแจ้งเตือนชั่วคราวแก่ผู้ใช้อย่างชัดเจนเป็นเรื่องไม่เหมาะสมหากหน้าเว็บอยู่ในสถานะซ่อน แม้ว่าตัวอย่างนี้จะเห็นชัดดี แต่ก็ยังมีคำแนะนำอื่นๆ ที่ไม่ชัดเจนจนต้องอธิบายเพิ่มเติม
รัฐ | คำแนะนำสำหรับนักพัฒนาซอฟต์แวร์ |
---|---|
Active |
สถานะใช้งานอยู่คือช่วงเวลาที่สำคัญที่สุดสำหรับผู้ใช้ ดังนั้นจึงเป็นเวลาที่สำคัญที่สุดสำหรับหน้าเว็บในการ ตอบสนองต่อข้อมูลจากผู้ใช้ งานใดก็ตามที่ไม่ได้ใช้ UI ที่อาจบล็อกเทรดหลักควรถูกลดลำดับความสำคัญเป็น ระยะเวลาที่ไม่มีการใช้งานหรือ โหลดไปยัง Web Worker |
Passive |
ในสถานะพาสซีฟ ผู้ใช้ไม่ได้โต้ตอบกับหน้าเว็บ แต่จะยังมองเห็นหน้าเว็บ ซึ่งหมายความว่าการอัปเดต UI และภาพเคลื่อนไหวควรจะยังคงดำเนินไปอย่างราบรื่น แต่ช่วงเวลาเมื่อมีการอัปเดตเหล่านี้เกิดขึ้นน้อยกว่า เมื่อหน้าเว็บเปลี่ยนจากแอ็กทีฟเป็นพาสซีฟ ก็ถึงเวลาที่จะคงสถานะของแอปพลิเคชันที่ไม่ได้บันทึกไว้ |
เมื่อหน้าเว็บเปลี่ยนจากพาสซีฟเป็นซ่อนแล้ว ผู้ใช้จะไม่โต้ตอบกับหน้าเว็บอีกจนกว่าจะโหลดซ้ำ การเปลี่ยนไปใช้การซ่อนมักเป็นการเปลี่ยนแปลงสถานะสุดท้ายที่นักพัฒนาแอปสังเกตได้ที่น่าเชื่อถือ (โดยเฉพาะอย่างยิ่งในอุปกรณ์เคลื่อนที่ เนื่องจากผู้ใช้ปิดแท็บหรือตัวแอปเบราว์เซอร์เอง และเหตุการณ์ ซึ่งหมายความว่าคุณควรถือว่าสถานะซ่อนอยู่น่าจะเป็นการสิ้นสุดเซสชันของผู้ใช้ กล่าวคือ ให้รักษาสถานะของแอปพลิเคชันที่ไม่ได้บันทึก และส่งข้อมูลวิเคราะห์ที่ยังไม่ได้ส่ง นอกจากนี้ คุณยังควรหยุดอัปเดต UI (เนื่องจากผู้ใช้จะไม่เห็น) และควรหยุดงานที่ผู้ใช้ไม่ต้องการให้ทำงานในเบื้องหลัง |
|
Frozen |
ในสถานะค้าง งานที่ตรึงได้ใน คิวงานจะถูกระงับจนกว่าหน้าเว็บจะไม่มีการใช้งาน ซึ่งอาจไม่เกิดขึ้นเลย (เช่น หากทิ้งหน้าเว็บไปแล้ว) ซึ่งหมายความว่าเมื่อหน้าเว็บเปลี่ยนจากซ่อนเป็นตรึงไว้ คุณต้องหยุดตัวจับเวลาหรือทำลายการเชื่อมต่อที่หากค้าง อาจส่งผลกระทบต่อแท็บอื่นๆ ที่เปิดอยู่ในต้นทางเดียวกัน หรือส่งผลกระทบต่อความสามารถของเบราว์เซอร์ในการนำหน้าเว็บไปไว้ใน Back-Forward Cache โดยเฉพาะอย่างยิ่ง คุณควรดำเนินการต่อไปนี้
นอกจากนี้ คุณควรคงสถานะมุมมองแบบไดนามิก (เช่น ตำแหน่งการเลื่อนในมุมมองรายการที่ไม่สิ้นสุด) ไปยัง
หากหน้าเว็บเปลี่ยนจากค้างกลับไปเป็นซ่อนไว้ คุณสามารถเปิดการเชื่อมต่อที่ปิดอยู่อีกครั้งหรือเริ่มต้นการสำรวจที่คุณหยุดไว้เมื่อหน้าเว็บหยุดทำงานในครั้งแรกได้ |
Terminated |
โดยทั่วไปแล้วคุณไม่จำเป็นต้องดำเนินการใดๆ เมื่อหน้าเว็บเปลี่ยนเป็นสถานะสิ้นสุด เนื่องจากระบบจะยกเลิกการโหลดหน้าอันเป็นผลมาจากการดำเนินการของผู้ใช้จะผ่านสถานะซ่อนก่อนเข้าสู่สถานะสิ้นสุด สถานะซ่อนจึงเป็นตำแหน่งที่ควรมีตรรกะสิ้นสุดเซสชัน (เช่น คงสถานะของแอปพลิเคชันไว้และการรายงานไปยังข้อมูลวิเคราะห์) นอกจากนี้ (ดังที่ระบุไว้ในคำแนะนำสำหรับสถานะซ่อน) สิ่งสำคัญอย่างยิ่งสำหรับนักพัฒนาซอฟต์แวร์ต้องตระหนักว่าการเปลี่ยนเป็นสถานะสิ้นสุดนั้นไม่สามารถตรวจพบได้อย่างน่าเชื่อถือในหลายกรณี (โดยเฉพาะบนอุปกรณ์เคลื่อนที่) ดังนั้นนักพัฒนาแอปที่อาศัยเหตุการณ์การสิ้นสุด (เช่น |
Discarded |
นักพัฒนาแอปไม่สามารถสังเกตสถานะยกเลิกแล้วในขณะที่หน้าเว็บกำลังถูกทิ้ง นั่นเป็นเพราะโดยทั่วไประบบจะทิ้งหน้าเว็บภายใต้ข้อจำกัดด้านทรัพยากร และการเลิกตรึงหน้าเพียงเพื่อให้สคริปต์ทำงานตอบสนองต่อเหตุการณ์การทิ้งไม่ได้ในกรณีส่วนใหญ่ คุณจึงควรเตรียมพร้อมสำหรับความเป็นไปได้ที่จะมีการทิ้งการเปลี่ยนแปลงจากซ่อนอยู่เป็นตรึงไว้ แล้วค่อยตอบสนองต่อการกู้คืนหน้าเว็บที่ยกเลิกไปแล้วเมื่อโหลดหน้าเว็บเสร็จโดยการตรวจสอบ |
ขอย้ำอีกครั้งว่าเนื่องจากความเสถียรและลำดับเหตุการณ์ในวงจรไม่ได้นำไปใช้งานในทุกเบราว์เซอร์ วิธีที่ง่ายที่สุดในการทำตามคำแนะนำในตารางคือการใช้ PageLifecycle.js
API วงจรเดิมที่ควรหลีกเลี่ยง
ควรหลีกเลี่ยงเหตุการณ์ต่อไปนี้หากเป็นไปได้
เหตุการณ์ยกเลิกการโหลด
นักพัฒนาซอฟต์แวร์จำนวนมากถือว่าเหตุการณ์ unload
เป็นการเรียกกลับที่รับประกันและใช้เป็นสัญญาณสิ้นสุดเซสชันเพื่อบันทึกสถานะและส่งข้อมูลวิเคราะห์ แต่การดำเนินการนี้ไม่น่าเชื่อถือมาก โดยเฉพาะบนอุปกรณ์เคลื่อนที่ เหตุการณ์ unload
จะไม่เริ่มทำงานในสถานการณ์การยกเลิกการโหลดโดยทั่วไป ซึ่งรวมถึงการปิดแท็บจากตัวสลับแท็บในอุปกรณ์เคลื่อนที่ หรือปิดแอปเบราว์เซอร์จากตัวสลับแอป
ด้วยเหตุนี้ คุณจึงควรใช้เหตุการณ์ visibilitychange
ในการพิจารณาว่าเซสชันจะสิ้นสุดเมื่อใด และพิจารณาสถานะที่ซ่อนอยู่ว่าเป็นเวลาที่เชื่อถือได้ครั้งสุดท้ายในการบันทึกแอปและข้อมูลผู้ใช้
นอกจากนี้ การมีเครื่องจัดการเหตุการณ์ unload
ที่ลงทะเบียนแล้ว (ผ่าน onunload
หรือ addEventListener()
) อาจทำให้เบราว์เซอร์ใส่หน้าใน Back/Forward Cache เพื่อให้โหลดย้อนกลับและไปข้างหน้าไม่ได้
สำหรับเบราว์เซอร์ที่ทันสมัยทั้งหมด ขอแนะนำให้ใช้เหตุการณ์ pagehide
เพื่อตรวจหาการยกเลิกการโหลดหน้าที่อาจเกิดขึ้น (หรือที่เรียกว่าสถานะสิ้นสุด) เสมอ ไม่ใช่เหตุการณ์ unload
หากจำเป็นต้องรองรับ Internet Explorer เวอร์ชัน 10 หรือต่ำกว่า คุณควรฟีเจอร์ตรวจหาเหตุการณ์ pagehide
และใช้ unload
ต่อเมื่อเบราว์เซอร์ไม่รองรับ pagehide
เท่านั้น โดยทำดังนี้
const terminationEvent = 'onpagehide' in self ? 'pagehide' : 'unload';
window.addEventListener(terminationEvent, (event) => {
// Note: if the browser is able to cache the page, `event.persisted`
// is `true`, and the state is frozen rather than terminated.
});
เหตุการณ์ beforeunload
เหตุการณ์ beforeunload
มีปัญหาคล้ายกับเหตุการณ์ unload
กล่าวคือ ที่ผ่านมาแล้ว การมีเหตุการณ์ beforeunload
อาจทำให้หน้าเว็บไม่มีสิทธิ์ใช้ Back/Forward Cache เบราว์เซอร์ที่ทันสมัย
จะไม่มีข้อจำกัดนี้ แม้ว่าการป้องกันบางเบราว์เซอร์จะไม่เริ่มการทำงานของเหตุการณ์ beforeunload
เมื่อพยายามใส่หน้าใน Back-Forward Cache ซึ่งหมายความว่าเหตุการณ์ไม่ถือว่าเป็นสัญญาณสิ้นสุดเซสชัน
นอกจากนี้ เบราว์เซอร์บางประเภท (รวมถึง Chrome) ยังต้องมีการโต้ตอบจากผู้ใช้ในหน้าเว็บก่อนที่จะอนุญาตให้เหตุการณ์ beforeunload
เริ่มทํางาน ซึ่งจะส่งผลต่อความเสถียรยิ่งขึ้น
ความแตกต่างหนึ่งระหว่าง beforeunload
และ unload
คือการใช้งาน beforeunload
ที่ถูกต้องตามกฎหมาย ตัวอย่างเช่น เมื่อคุณต้องการเตือนผู้ใช้ว่ามีการเปลี่ยนแปลงที่ไม่ได้บันทึก การเปลี่ยนแปลงเหล่านั้นจะสูญหายหากพวกเขายังคงยกเลิกการโหลดหน้าเว็บอยู่
เนื่องจากมีเหตุผลอันสมควรในการใช้ beforeunload
เราจึงขอแนะนำให้คุณเพิ่ม Listener beforeunload
เท่านั้นเมื่อผู้ใช้มีการเปลี่ยนแปลงที่ยังไม่ได้บันทึก จากนั้นนำออกทันทีหลังบันทึกแล้ว
กล่าวคือ อย่าทำแบบนี้ (เพราะจะเพิ่ม Listener beforeunload
โดยไม่มีเงื่อนไข)
addEventListener('beforeunload', (event) => {
// A function that returns `true` if the page has unsaved changes.
if (pageHasUnsavedChanges()) {
event.preventDefault();
// Legacy support for older browsers.
return (event.returnValue = true);
}
});
ให้ทำเช่นนี้แทน (เพราะระบบจะเพิ่ม Listener beforeunload
เมื่อจำเป็นเท่านั้นและนำออกเมื่อไม่จำเป็น)
const beforeUnloadListener = (event) => {
event.preventDefault();
// Legacy support for older browsers.
return (event.returnValue = true);
};
// A function that invokes a callback when the page has unsaved changes.
onPageHasUnsavedChanges(() => {
addEventListener('beforeunload', beforeUnloadListener);
});
// A function that invokes a callback when the page's unsaved changes are resolved.
onAllChangesSaved(() => {
removeEventListener('beforeunload', beforeUnloadListener);
});
คำถามที่พบบ่อย
ทำไมจึงไม่มีสถานะ "กำลังโหลด"
Page Lifecycle API กำหนดสถานะที่แยกจากกันและแยกกัน เนื่องจากสามารถโหลดหน้าเว็บได้ในสถานะ "ใช้งานอยู่" "แพสซีฟ" หรือ "ซ่อน" ทั้งยังสามารถเปลี่ยนสถานะหรือสิ้นสุดการใช้งานได้ ก่อนที่หน้าจะโหลดเสร็จ สถานะการโหลดแยกต่างหากจึงไม่เหมาะกับรูปแบบเช่นนี้
หน้าของฉันทำงานสำคัญเมื่อซ่อนไว้ ฉันจะหยุดไม่ให้หยุดหรือทิ้งหน้าเว็บได้อย่างไร
มีเหตุผลหลายประการที่คุณไม่ควรหยุดหน้าเว็บชั่วคราวขณะทำงานในสถานะที่ซ่อนไว้ ตัวอย่างที่เห็นได้ชัดที่สุดคือแอปที่เปิดเพลง
นอกจากนี้ยังมีสถานการณ์ที่ Chrome อาจทิ้งหน้าเว็บ เช่น หากมีแบบฟอร์มที่มีการป้อนข้อมูลจากผู้ใช้ที่ยังไม่ได้ส่ง หรือมีตัวแฮนเดิล beforeunload
ที่เตือนเมื่อยกเลิกการโหลดหน้าเว็บ
ในตอนนี้ Chrome จะเลือกระมัดระวังเมื่อทิ้งหน้าเว็บ และจะต้องทำเมื่อมั่นใจว่าจะไม่ส่งผลต่อผู้ใช้ ตัวอย่างเช่น ระบบจะไม่ยกเลิกหน้าเว็บที่พบว่าดำเนินการอย่างใดอย่างหนึ่งต่อไปนี้ขณะอยู่ในสถานะซ่อน ยกเว้นกรณีที่มีข้อจำกัดด้านทรัพยากรสูงสุด
- กำลังเล่นเสียง
- การใช้ WebRTC
- การอัปเดตชื่อตารางหรือไอคอน Fav
- การแสดงการแจ้งเตือน
- การส่งข้อความ Push
สำหรับฟีเจอร์รายการในปัจจุบันที่ใช้พิจารณาว่าแท็บควรถูกตรึงหรือทิ้งอย่างปลอดภัยหรือไม่ โปรดดูการเรียนรู้สำหรับการตรึงและทิ้งใน Chrome
Back-Forward Cache เป็นคำที่ใช้อธิบายการเพิ่มประสิทธิภาพการนำทางในบางเบราว์เซอร์ ซึ่งทำให้ใช้ปุ่มย้อนกลับและปุ่มไปข้างหน้าได้เร็วขึ้น
เมื่อผู้ใช้ออกจากหน้า เบราว์เซอร์เหล่านี้จะตรึงเวอร์ชันของหน้านั้นเพื่อให้กลับมาดำเนินการต่อได้อย่างรวดเร็วในกรณีที่ผู้ใช้ย้อนกลับโดยใช้ปุ่มย้อนกลับหรือไปข้างหน้า โปรดทราบว่าการเพิ่มเครื่องจัดการเหตุการณ์ unload
จะทำให้ไม่สามารถเพิ่มประสิทธิภาพนี้ได้
สำหรับจุดประสงค์และวัตถุประสงค์ทั้งหมด การหยุดทำงานนี้จะมีการทำงานเหมือนกับการหยุดทำงานของเบราว์เซอร์เพื่อประหยัด CPU/แบตเตอรี่ ด้วยเหตุนี้จึงถือว่าเป็นส่วนหนึ่งของสถานะวงจรที่ค้างด้วย
หากเรียกใช้ API แบบไม่พร้อมกันในสถานะที่ตรึงหรือสิ้นสุดแล้ว ฉันจะบันทึกข้อมูลลงใน IndexedDB ได้อย่างไร
ในสถานะที่หยุดนิ่งและสิ้นสุดแล้ว ระบบจะระงับงานที่ฟรีได้ในคิวงานของหน้าเว็บ ซึ่งหมายความว่าจะใช้ API แบบอะซิงโครนัสและตามโค้ดเรียกกลับ เช่น IndexedDB อย่างไม่น่าไว้วางใจ
ในอนาคต เราจะเพิ่มเมธอด commit()
ลงในออบเจ็กต์ IDBTransaction
ซึ่งจะช่วยให้นักพัฒนาซอฟต์แวร์มีวิธีดำเนินการธุรกรรมแบบเขียนเท่านั้นที่มีประสิทธิภาพซึ่งไม่จำเป็นต้องมีการเรียกกลับ กล่าวคือ หากนักพัฒนาซอฟต์แวร์เพียงแค่เขียนข้อมูลไปยัง IndexedDB และไม่ได้ทำธุรกรรมที่ซับซ้อนซึ่งประกอบด้วยการอ่านและเขียน เมธอด commit()
จะดำเนินการให้เสร็จสิ้นได้ก่อนที่คิวงานจะถูกระงับ (สมมติว่าเปิดฐานข้อมูล IndexedDB ไว้แล้ว)
แต่สำหรับโค้ดที่ต้องใช้งานได้ในปัจจุบัน นักพัฒนาซอฟต์แวร์จะมี 2 ตัวเลือก ได้แก่
- ใช้พื้นที่เก็บข้อมูลเซสชัน: พื้นที่เก็บข้อมูลเซสชันเป็นแบบซิงโครนัสและยังคงอยู่ในการทิ้งหน้าเว็บ
- ใช้ IndexedDB จาก Service Worker: โปรแกรมทำงานของบริการสามารถเก็บข้อมูลใน IndexedDB หลังจากที่หน้าถูกยกเลิกหรือยกเลิกแล้ว ใน Listener เหตุการณ์
freeze
หรือpagehide
คุณจะส่งข้อมูลไปยัง Service Worker ผ่านpostMessage()
ได้ และ Service Worker ก็สามารถบันทึกข้อมูลได้
การทดสอบแอปอยู่ในสถานะค้างและถูกยกเลิก
หากต้องการทดสอบลักษณะการทำงานของแอปในสถานะที่ค้างและยกเลิกแล้ว คุณสามารถไปที่
chrome://discards
เพื่อตรึงหรือทิ้งแท็บที่เปิดอยู่ได้
วิธีนี้ช่วยให้มั่นใจได้ว่าหน้าเว็บจะจัดการกับเหตุการณ์ freeze
และ resume
ได้อย่างถูกต้อง รวมถึงแฟล็ก document.wasDiscarded
เมื่อมีการโหลดหน้าเว็บซ้ำหลังการทิ้ง
สรุป
นักพัฒนาแอปที่ต้องการเคารพทรัพยากรระบบของอุปกรณ์ของผู้ใช้ควรสร้างแอปโดยคำนึงถึงสถานะของวงจรของหน้า หน้าเว็บต้องไม่ใช้ทรัพยากรระบบมากเกินไปในสถานการณ์ที่ผู้ใช้ไม่คาดคิด
ยิ่งนักพัฒนาซอฟต์แวร์เริ่มใช้ Page Lifecycle API ใหม่มากเท่าใด เบราว์เซอร์ก็จะหยุดทำงานและทิ้งหน้าที่ไม่ได้ใช้งานก็จะยิ่งปลอดภัยยิ่งขึ้น ซึ่งหมายความว่าเบราว์เซอร์จะใช้หน่วยความจำ, CPU, แบตเตอรี่ และทรัพยากรเครือข่ายน้อยลง ซึ่งเป็นข้อดีสำหรับผู้ใช้