Back-Forward Cache (หรือ bfcache) คือการเพิ่มประสิทธิภาพเบราว์เซอร์ที่ช่วยให้ไปข้างหน้าและย้อนกลับไปยังส่วนต่างๆ ได้ทันที ซึ่งปรับปรุงประสบการณ์การท่องเว็บได้อย่างมาก โดยเฉพาะผู้ใช้ที่ใช้เครือข่ายหรืออุปกรณ์ที่ช้า
ในฐานะนักพัฒนาเว็บ คุณต้องเข้าใจวิธีเพิ่มประสิทธิภาพหน้าเว็บสำหรับ bfcache เพื่อให้ผู้ใช้ได้รับประโยชน์
ความเข้ากันได้กับเบราว์เซอร์
เบราว์เซอร์หลักทั้งหมดมี bfcache รวมถึง Chrome ตั้งแต่เวอร์ชัน 96, Firefox และ Safari
ข้อมูลเบื้องต้นเกี่ยวกับ bfcache
เมื่อใช้ Back-Forward Cache (bfcache) เราจะเลื่อนการทำลายหน้าเว็บและหยุดการดำเนินการ JS ชั่วคราวแทนการทำลายหน้าเว็บเมื่อผู้ใช้ออกจากหน้าเว็บ หากผู้ใช้กลับมาในเร็วๆ นี้ เราจะทำให้หน้าเว็บแสดงอีกครั้งและยกเลิกการหยุดชั่วคราวการดำเนินการ JS ซึ่งจะทําให้ผู้ใช้ไปยังส่วนต่างๆ ของหน้าเว็บได้แทบจะทันที
คุณเคยเข้าชมเว็บไซต์และคลิกลิงก์เพื่อไปยังหน้าอื่นกี่ครั้ง แต่กลับพบว่าไม่ใช่สิ่งที่ต้องการและคลิกปุ่มย้อนกลับ ในขณะนั้น bfcache จะสร้างความแตกต่างอย่างมากในเรื่องความเร็วในการโหลดหน้าก่อนหน้า
| ไม่ได้เปิดใช้ bfcache | ระบบจะเริ่มคำขอใหม่เพื่อโหลดหน้าก่อนหน้า และเบราว์เซอร์อาจต้องดาวน์โหลดซ้ำ แยกวิเคราะห์ซ้ำ และเรียกใช้ซ้ำสำหรับทรัพยากรบางส่วน (หรือทั้งหมด) ที่เพิ่งดาวน์โหลดไป ทั้งนี้ขึ้นอยู่กับว่าหน้าเว็บนั้น ได้รับการเพิ่มประสิทธิภาพสำหรับการเข้าชมซ้ำได้ดีเพียงใด |
| เมื่อเปิดใช้ bfcache | การโหลดหน้าก่อนหน้าจะรวดเร็วมาก เนื่องจากสามารถกู้คืนทั้งหน้าจากหน่วยความจำได้โดยไม่ต้องไปที่เครือข่ายเลย |
ดูวิดีโอนี้เกี่ยวกับ bfcache ที่ใช้งานจริงเพื่อทำความเข้าใจการเพิ่มความเร็วในการไปยังส่วนต่างๆ
ในวิดีโอ ตัวอย่างที่มี bfcache จะเร็วกว่าตัวอย่างที่ไม่มี bfcache มาก
bfcache ไม่เพียงช่วยให้การไปยังส่วนต่างๆ เร็วขึ้น แต่ยังช่วยลดการใช้อินเทอร์เน็ตด้วย เนื่องจากไม่ต้องดาวน์โหลดทรัพยากรอีกครั้ง
ข้อมูลการใช้งาน Chrome แสดงให้เห็นว่าการไปยังส่วนต่างๆ บนเดสก์ท็อป 1 ใน 10 ครั้ง และบนอุปกรณ์เคลื่อนที่ 1 ใน 5 ครั้งเป็นการย้อนกลับหรือไปข้างหน้า เมื่อเปิดใช้ bfcache เบราว์เซอร์จะขจัดการโอนข้อมูลและเวลาที่ใช้ในการโหลดหน้าเว็บหลายพันล้านหน้าในทุกๆ วันได้
วิธีการทำงานของ "แคช"
"แคช" ที่ bfcache ใช้แตกต่างจากแคช HTTP ซึ่งมีบทบาทของตัวเองในการเร่งการไปยังส่วนต่างๆ ซ้ำ bfcache คือภาพรวมของทั้งหน้าในหน่วยความจำ รวมถึงฮีป JavaScript ในขณะที่แคช HTTP มีเฉพาะการตอบกลับสำหรับคำขอที่ส่งก่อนหน้านี้ เนื่องจากคำขอทั้งหมดที่จำเป็นในการโหลดหน้าเว็บนั้นแทบจะไม่ได้รับการตอบสนองจากแคช HTTP เลย การเข้าชมซ้ำโดยใช้การคืนค่า bfcache จึงเร็วกว่าการไปยังส่วนต่างๆ ที่ไม่ใช่ bfcache ที่ได้รับการเพิ่มประสิทธิภาพอย่างดีที่สุดเสมอ
การระงับหน้าเพื่ออาจเปิดใช้อีกครั้งในภายหลังมีความซับซ้อนในแง่ของวิธีที่ดีที่สุดในการเก็บรักษารหัสที่อยู่ระหว่างดำเนินการ เช่น คุณจะจัดการsetTimeout()การเรียกที่หมดเวลาขณะที่หน้าเว็บอยู่ใน bfcache อย่างไร
คำตอบคือเบราว์เซอร์จะหยุดตัวจับเวลาที่รอดำเนินการหรือสัญญาที่ยังไม่ได้รับการแก้ไขสำหรับหน้าเว็บใน bfcache รวมถึงงานที่รอดำเนินการเกือบทั้งหมดในคิวงาน JavaScript และจะกลับมาประมวลผลงานต่อหากมีการกู้คืนหน้าเว็บจาก bfcache
ในบางกรณี เช่น การหมดเวลาและสัญญา ความเสี่ยงค่อนข้างต่ำ แต่ในกรณีอื่นๆ อาจทำให้เกิดพฤติกรรมที่สับสนหรือไม่คาดคิด ตัวอย่างเช่น หากเบราว์เซอร์หยุดงานชั่วคราวซึ่งจำเป็นในธุรกรรม IndexedDB ก็อาจส่งผลต่อแท็บอื่นๆ ที่เปิดอยู่ในต้นทางเดียวกัน เนื่องจากหลายแท็บเข้าถึงฐานข้อมูล IndexedDB เดียวกันได้พร้อมกัน ด้วยเหตุนี้ โดยทั่วไปแล้วเบราว์เซอร์จะไม่พยายามแคชหน้าเว็บในระหว่างธุรกรรม IndexedDB หรือขณะใช้ API ที่อาจส่งผลต่อหน้าเว็บอื่นๆ
ดูรายละเอียดเพิ่มเติมเกี่ยวกับวิธีที่การใช้งาน API ต่างๆ ส่งผลต่อการมีสิทธิ์ใช้ bfcache ของหน้าเว็บได้ที่เพิ่มประสิทธิภาพหน้าเว็บสำหรับ bfcache
bfcache และ iframe
หากหน้าเว็บมี iframe แบบฝัง iframe เองจะไม่มีสิทธิ์ใช้ bfcache แยกกัน เช่น หากคุณไปยัง URL อื่นภายใน iframe เนื้อหาก่อนหน้าจะไม่เข้าสู่ bfcache และหากคุณย้อนกลับ เบราว์เซอร์จะ "ย้อนกลับ" ภายใน iframe แทนที่จะเป็นในเฟรมหลัก แต่การนำทางย้อนกลับภายใน iframe จะไม่ใช้ bfcache
อย่างไรก็ตาม เมื่อมีการคืนค่าเฟรมหลักจาก bfcache ระบบจะคืนค่า iframe ที่ฝังไว้ตามสถานะเมื่อหน้าเว็บเข้าสู่ bfcache
นอกจากนี้ ยังบล็อกเฟรมหลักไม่ให้ใช้ bfcache ได้ด้วยหาก iframe ที่ฝังใช้ API ที่บล็อกการทำงานนี้ คุณสามารถใช้นโยบายสิทธิ์ที่ตั้งค่าไว้ในเฟรมหลักหรือใช้sandboxแอตทริบิวต์เพื่อหลีกเลี่ยงปัญหานี้ได้
bfcache และแอปหน้าเว็บเดียว (SPA)
เนื่องจาก bfcache ทำงานกับการนำทางที่เบราว์เซอร์จัดการ จึงใช้กับ "การนำทางแบบย่อ" ภายในแอปหน้าเว็บเดียว (SPA) ไม่ได้ อย่างไรก็ตาม bfcache ยังคงช่วยได้เมื่อกลับไปที่ SPA แทนที่จะเริ่มต้นแอปนั้นใหม่ทั้งหมดตั้งแต่ต้น
API สำหรับสังเกต bfcache
แม้ว่า bfcache จะเป็นการเพิ่มประสิทธิภาพที่เบราว์เซอร์ทําโดยอัตโนมัติ แต่ก็ยังคงมีความสําคัญที่นักพัฒนาซอฟต์แวร์ควรทราบว่าเมื่อใดที่เกิดเหตุการณ์นี้ขึ้น เพื่อที่จะได้เพิ่มประสิทธิภาพหน้าเว็บสําหรับ bfcache และปรับเมตริกหรือการวัดประสิทธิภาพตามความเหมาะสม
เหตุการณ์หลักที่ใช้สังเกต bfcache คือเหตุการณ์การเปลี่ยนหน้า pageshow และ pagehide ซึ่งเบราว์เซอร์ส่วนใหญ่รองรับ
นอกจากนี้ ระบบยังส่งเหตุการณ์ วงจรหน้าเว็บ ที่ใหม่กว่าอย่าง freeze และ resume เมื่อหน้าเว็บเข้าหรือออกจาก bfcache รวมถึงในสถานการณ์อื่นๆ ด้วย เช่น เมื่อแท็บที่อยู่เบื้องหลังถูกหยุดชั่วคราวเพื่อลดการใช้งาน CPU เหตุการณ์เหล่านี้ใช้ได้เฉพาะในเบราว์เซอร์ที่พัฒนาบน Chromium
สังเกตเมื่อมีการกู้คืนหน้าเว็บจาก bfcache
เหตุการณ์ pageshow จะทริกเกอร์ทันทีหลังจากเหตุการณ์ load เมื่อหน้าเว็บโหลดครั้งแรกและทุกครั้งที่กู้คืนหน้าเว็บจาก bfcache เหตุการณ์ pageshow มีพร็อพเพอร์ตี้ persisted ซึ่งเป็น true หากมีการกู้คืนหน้าจาก bfcache และเป็น false ในกรณีอื่นๆ คุณใช้พร็อพเพอร์ตี้ persisted เพื่อแยกความแตกต่างระหว่างการโหลดหน้าเว็บปกติกับการคืนค่า bfcache ได้ เช่น
window.addEventListener('pageshow', (event) => {
if (event.persisted) {
console.log('This page was restored from the bfcache.');
} else {
console.log('This page was loaded normally.');
}
});
ในเบราว์เซอร์ที่รองรับ Page Lifecycle API เหตุการณ์ resume จะทริกเกอร์เมื่อมีการกู้คืนหน้าเว็บจาก bfcache (ก่อนเหตุการณ์ pageshow ทันที) และเมื่อผู้ใช้กลับมาที่แท็บพื้นหลังที่หยุดทำงาน หากต้องการอัปเดตสถานะของหน้าเว็บหลังจากที่ระบบหยุดการทำงานชั่วคราว (รวมถึงหน้าเว็บใน bfcache) คุณสามารถใช้เหตุการณ์ resume ได้ แต่หากต้องการวัดอัตราการเข้าชม bfcache ของเว็บไซต์ คุณจะต้องใช้เหตุการณ์ pageshow ในบางกรณี คุณอาจต้องใช้ทั้ง 2 อย่าง
ดูรายละเอียดเกี่ยวกับแนวทางปฏิบัติแนะนำในการวัด bfcache ได้ที่วิธีที่ bfcache ส่งผลต่อการวิเคราะห์และการวัดประสิทธิภาพ
สังเกตเมื่อหน้าเว็บเข้าสู่ bfcache
pagehide เหตุการณ์จะเริ่มทำงานเมื่อหน้าเว็บยกเลิกการโหลดหรือเมื่อเบราว์เซอร์พยายามใส่หน้าเว็บใน bfcache
เหตุการณ์ pagehide มีพร็อพเพอร์ตี้ persisted ด้วย หากเป็น false แสดงว่าหน้าเว็บนั้นไม่ได้กำลังจะเข้าสู่ bfcache อย่างไรก็ตาม persistedการเป็น true ไม่ได้รับประกันว่าหน้าเว็บจะได้รับการแคช ซึ่งหมายความว่าเบราว์เซอร์ตั้งใจที่จะแคชหน้าเว็บ แต่ก็อาจมีปัจจัยอื่นๆ ที่ทำให้แคชไม่ได้
window.addEventListener('pagehide', (event) => {
if (event.persisted) {
console.log('This page *might* be entering the bfcache.');
} else {
console.log('This page will unload normally and be discarded.');
}
});
ในทํานองเดียวกัน เหตุการณ์ freeze จะเริ่มทํางานทันทีหลังจากเหตุการณ์ pagehide หาก persisted เป็น true แต่ก็หมายความว่าเบราว์เซอร์ตั้งใจที่จะแคชหน้าเว็บเท่านั้น แต่ก็อาจต้องทิ้งไปเนื่องจากเหตุผลหลายประการที่จะอธิบายในภายหลัง
เพิ่มประสิทธิภาพหน้าเว็บสำหรับ bfcache
ระบบจะไม่จัดเก็บทุกหน้าเว็บไว้ใน bfcache และแม้ว่าระบบจะจัดเก็บหน้าเว็บไว้ในนั้น แต่หน้าเว็บดังกล่าวก็จะไม่คงอยู่ใน bfcache ไปเรื่อยๆ นักพัฒนาซอฟต์แวร์จำเป็นต้องเข้าใจว่าอะไรที่ทำให้หน้าเว็บมีสิทธิ์ (และไม่มีสิทธิ์) สำหรับ bfcache เพื่อเพิ่มอัตราการเข้าชมแคชให้ได้มากที่สุด
ส่วนต่อไปนี้จะอธิบายแนวทางปฏิบัติแนะนำเพื่อให้เบราว์เซอร์แคชหน้าเว็บของคุณได้มากที่สุด
ห้ามใช้เหตุการณ์ unload
วิธีที่สําคัญที่สุดในการเพิ่มประสิทธิภาพ bfcache ในเบราว์เซอร์ทั้งหมดคือการไม่ใช้เหตุการณ์ unload ตลอดไป
เหตุการณ์ unload เป็นปัญหาสำหรับเบราว์เซอร์เนื่องจากมีมาก่อน bfcache และหน้าเว็บจำนวนมากบนอินเทอร์เน็ตทำงานภายใต้สมมติฐาน (ที่สมเหตุสมผล) ว่าหน้าเว็บจะไม่ยังคงอยู่หลังจากที่เหตุการณ์ unload เริ่มทำงาน ซึ่งเป็นความท้าทายเนื่องจากหน้าเว็บจำนวนมากยังสร้างขึ้นโดยสมมติว่าเหตุการณ์ unload จะทริกเกอร์ทุกครั้งที่ผู้ใช้นำทางออกจากหน้าเว็บ ซึ่งไม่เป็นความจริงอีกต่อไป (และไม่เป็นความจริงมาเป็นเวลานานแล้ว)
ดังนั้นเบราว์เซอร์จึงต้องเผชิญกับภาวะกลืนไม่เข้าคายไม่ออก โดยต้องเลือกระหว่างสิ่งที่ปรับปรุงประสบการณ์ของผู้ใช้ได้ แต่ก็อาจเสี่ยงต่อการทำให้หน้าเว็บใช้งานไม่ได้ด้วย
ในเดสก์ท็อป Chrome และ Firefox เลือกที่จะทำให้หน้าเว็บไม่มีสิทธิ์ใช้ bfcache หากเพิ่มunload ซึ่งมีความเสี่ยงน้อยกว่า แต่ก็ทำให้หน้าเว็บจำนวนมากไม่มีสิทธิ์ด้วย Safari จะพยายามแคชบางหน้าด้วยเครื่องมือฟังเหตุการณ์ unload แต่เพื่อลดการหยุดทำงานที่อาจเกิดขึ้น จึงจะไม่เรียกใช้เหตุการณ์ unload เมื่อผู้ใช้นำทางออก ซึ่งทำให้เหตุการณ์ไม่น่าเชื่อถืออย่างมาก
ในอุปกรณ์เคลื่อนที่ Chrome และ Safari จะพยายามแคชหน้าเว็บที่มีเครื่องมือฟังเหตุการณ์ unload เนื่องจากความเสี่ยงที่จะเกิดการหยุดทำงานนั้นต่ำกว่าเพราะเหตุการณ์ unload ไม่น่าเชื่อถืออย่างยิ่งในอุปกรณ์เคลื่อนที่มาโดยตลอด Firefox ถือว่าหน้าที่ใช้ unload ไม่มีสิทธิ์ใช้ bfcache ยกเว้นใน iOS ซึ่งกำหนดให้เบราว์เซอร์ทั้งหมดต้องใช้เครื่องมือแสดงผล WebKit จึงทำงานเหมือน Safari
ให้ใช้เหตุการณ์ pagehide แทนเหตุการณ์ unload เหตุการณ์ pagehide จะทํางานในทุกกรณีที่เหตุการณ์ unload ทํางาน และยังทํางานเมื่อมีการใส่หน้าเว็บใน bfcache ด้วย
ในความเป็นจริงแล้ว Lighthouse มีการตรวจสอบ no-unload-listeners ซึ่งจะเตือนนักพัฒนาซอฟต์แวร์หาก JavaScript ในหน้าเว็บ (รวมถึง JavaScript จากไลบรารีของบุคคลที่สาม) เพิ่มเครื่องมือฟังเหตุการณ์ unload
Chrome กำลังพิจารณาเลิกใช้งานเหตุการณ์ unload เนื่องจากความไม่น่าเชื่อถือและผลกระทบต่อประสิทธิภาพของ bfcache
ใช้นโยบายสิทธิ์เพื่อป้องกันไม่ให้ใช้ตัวแฮนเดิลการยกเลิกการโหลดในหน้าเว็บ
เว็บไซต์ที่ไม่ได้ใช้ตัวแฮนเดิลเหตุการณ์ unload สามารถตรวจสอบว่าไม่มีการเพิ่มตัวแฮนเดิลเหล่านี้ได้โดยใช้นโยบายสิทธิ์
Permissions-Policy: unload=()
นอกจากนี้ ยังช่วยป้องกันไม่ให้บุคคลที่สามหรือส่วนขยายทำให้เว็บไซต์ช้าลงด้วยการเพิ่มตัวแฮนเดิลการเลิกโหลด และทำให้เว็บไซต์ไม่มีสิทธิ์ใช้ bfcache
เพิ่มเครื่องฟัง beforeunload แบบมีเงื่อนไขเท่านั้น
เหตุการณ์ beforeunload จะไม่ทำให้หน้าเว็บของคุณไม่มีสิทธิ์ใช้ bfcache ใน bfcache ของเบราว์เซอร์สมัยใหม่ แต่ก่อนหน้านี้เหตุการณ์ดังกล่าวทำให้หน้าเว็บไม่มีสิทธิ์ใช้ bfcache และยังคงไม่น่าเชื่อถือ ดังนั้นโปรดหลีกเลี่ยงการใช้เหตุการณ์นี้เว้นแต่จะจำเป็นจริงๆ
อย่างไรก็ตาม beforeunload มีการใช้งานที่ถูกต้องตามกฎหมาย ซึ่งต่างจากเหตุการณ์ unload
เช่น เมื่อคุณต้องการเตือนผู้ใช้ว่ามี
การเปลี่ยนแปลงที่ไม่ได้บันทึกซึ่งจะหายไปหากผู้ใช้ออกจากหน้าเว็บ ในกรณีนี้ เราขอแนะนําให้คุณเพิ่ม beforeunload Listener เฉพาะเมื่อผู้ใช้มีการเปลี่ยนแปลงที่ไม่ได้บันทึก
และนําออกทันทีหลังจากบันทึกการเปลี่ยนแปลงที่ไม่ได้บันทึกแล้ว
window.addEventListener('beforeunload', (event) => { if (pageHasUnsavedChanges()) { event.preventDefault(); return event.returnValue = 'Are you sure you want to exit?'; } });
beforeunload โดยไม่มีเงื่อนไข
function beforeUnloadListener(event) { event.preventDefault(); return event.returnValue = 'Are you sure you want to exit?'; }; // A function that invokes a callback when the page has unsaved changes. onPageHasUnsavedChanges(() => { window.addEventListener('beforeunload', beforeUnloadListener); }); // A function that invokes a callback when the page's unsaved changes are resolved. onAllChangesSaved(() => { window.removeEventListener('beforeunload', beforeUnloadListener); });
beforeunload เมื่อจำเป็นเท่านั้น (และ
นำออกเมื่อไม่จำเป็น)
ลดการใช้ Cache-Control: no-store
Cache-Control: no-store คือส่วนหัว HTTP ที่เว็บเซิร์ฟเวอร์ตั้งค่าในการตอบกลับเพื่อสั่งให้เบราว์เซอร์ไม่จัดเก็บการตอบกลับในแคช HTTP ใช้สำหรับทรัพยากรที่มีข้อมูลผู้ใช้ที่ละเอียดอ่อน เช่น หน้าเว็บที่ต้องเข้าสู่ระบบ
แม้ว่า bfcache จะไม่ใช่แคช HTTP แต่ในอดีตเมื่อตั้งค่า Cache-Control: no-store ในทรัพยากรหน้าเว็บเอง (ไม่ใช่ทรัพยากรย่อย) เบราว์เซอร์จะเลือกไม่จัดเก็บหน้าเว็บใน bfcache ดังนั้นหน้าเว็บที่ใช้ Cache-Control: no-store อาจไม่มีสิทธิ์ใช้ bfcache ขณะนี้เรากำลังดำเนินการเพื่อเปลี่ยนลักษณะการทำงานนี้สำหรับ Chrome ในลักษณะที่รักษาความเป็นส่วนตัว
เนื่องจาก Cache-Control: no-store จำกัดการมีสิทธิ์ของหน้าสำหรับ bfcache จึงควรตั้งค่าเฉพาะในหน้าที่มีข้อมูลที่ละเอียดอ่อนซึ่งไม่ควรแคชในทุกกรณี
สำหรับหน้าเว็บที่ต้องแสดงเนื้อหาล่าสุดอยู่เสมอและเนื้อหานั้นไม่มีข้อมูลที่ละเอียดอ่อน ให้ใช้ Cache-Control: no-cache หรือ Cache-Control: max-age=0 คำสั่งเหล่านี้จะสั่งให้เบราว์เซอร์ตรวจสอบเนื้อหาอีกครั้งก่อนแสดง และจะไม่ส่งผลต่อการมีสิทธิ์ใช้ bfcache ของหน้าเว็บ
โปรดทราบว่าเมื่อมีการคืนค่าหน้าเว็บจาก bfcache ระบบจะคืนค่าจากหน่วยความจำ ไม่ใช่จากแคช HTTP ด้วยเหตุนี้ ระบบจึงไม่พิจารณาคำสั่งอย่าง Cache-Control: no-cache หรือ Cache-Control: max-age=0 และจะไม่มีการตรวจสอบซ้ำก่อนที่จะแสดงเนื้อหาต่อผู้ใช้
อย่างไรก็ตาม วิธีนี้ยังคงมีแนวโน้มที่จะมอบประสบการณ์การใช้งานที่ดีกว่า เนื่องจาก bfcache จะคืนค่าทันที และเนื้อหาไม่น่าจะล้าสมัยเนื่องจากหน้าเว็บไม่ได้อยู่ใน bfcache นานนัก อย่างไรก็ตาม หากเนื้อหามีการเปลี่ยนแปลงทุกนาที คุณสามารถดึงข้อมูลอัปเดตได้โดยใช้pageshow เหตุการณ์ตามที่ระบุไว้ในส่วนถัดไป
อัปเดตข้อมูลที่ล้าสมัยหรือข้อมูลที่ละเอียดอ่อนหลังจากกู้คืน bfcache
หากเว็บไซต์ของคุณเก็บสถานะของผู้ใช้ โดยเฉพาะข้อมูลที่ละเอียดอ่อนของผู้ใช้ ข้อมูลดังกล่าวจะต้องได้รับการอัปเดตหรือล้างหลังจากที่กู้คืนหน้าเว็บจาก bfcache
ตัวอย่างเช่น หากผู้ใช้นำทางไปยังหน้าชำระเงินแล้วอัปเดตรถเข็นช็อปปิ้ง การนำทางย้อนกลับอาจแสดงข้อมูลที่ล้าสมัยหากมีการกู้คืนหน้าเก่าจาก bfcache
อีกตัวอย่างที่สำคัญกว่าคือหากผู้ใช้ลงชื่อออกจากเว็บไซต์ในคอมพิวเตอร์สาธารณะและผู้ใช้รายถัดไปคลิกปุ่มย้อนกลับ ซึ่งอาจทำให้ข้อมูลส่วนตัวที่ผู้ใช้คิดว่าระบบล้างไปแล้วเมื่อออกจากระบบปรากฏขึ้น
เพื่อหลีกเลี่ยงสถานการณ์เช่นนี้ คุณควรจะอัปเดตหน้าเว็บเสมอหลังจากเหตุการณ์ pageshow หาก event.persisted เป็น true
window.addEventListener('pageshow', (event) => {
if (event.persisted) {
// Do any checks and updates to the page
}
});
แม้ว่าในอุดมคติแล้วคุณควรจะอัปเดตเนื้อหาในตำแหน่งเดิม แต่สำหรับการเปลี่ยนแปลงบางอย่าง คุณอาจต้องบังคับให้โหลดซ้ำแบบเต็ม โค้ดต่อไปนี้จะตรวจสอบว่ามีคุกกี้เฉพาะเว็บไซต์ในเหตุการณ์ pageshow หรือไม่ และจะโหลดซ้ำหากไม่พบคุกกี้
window.addEventListener('pageshow', (event) => {
if (event.persisted && !document.cookie.match(/my-cookie)) {
// Force a reload if the user has logged out.
location.reload();
}
});
การโหลดซ้ำมีข้อดีคือจะยังคงเก็บประวัติไว้ (เพื่อให้ไปยังหน้าถัดไปได้) แต่การเปลี่ยนเส้นทางอาจเหมาะสมกว่าในบางกรณี
โฆษณาและการคืนค่า bfcache
คุณอาจอยากหลีกเลี่ยงการใช้ bfcache เพื่อแสดงโฆษณาชุดใหม่ในการไปยังส่วนต่างๆ แบบย้อนกลับ/ไปข้างหน้าแต่ละครั้ง อย่างไรก็ตาม นอกเหนือจากผลกระทบต่อประสิทธิภาพแล้ว ยังเป็นที่น่าสงสัยว่าพฤติกรรมดังกล่าวจะนำไปสู่การมีส่วนร่วมกับโฆษณาที่ดีขึ้นหรือไม่ ผู้ใช้อาจเห็นโฆษณาที่ตั้งใจจะกลับมาคลิก แต่เมื่อโหลดซ้ำแทนที่จะกู้คืนจาก bfcache ผู้ใช้ก็จะไม่สามารถคลิกได้ การทดสอบสถานการณ์นี้ (ควรใช้การทดสอบ A/B) เป็นสิ่งสำคัญก่อนที่จะสรุป
สำหรับเว็บไซต์ที่ต้องการรีเฟรชโฆษณาเมื่อมีการคืนค่า bfcache การรีเฟรชเฉพาะโฆษณาในเหตุการณ์ pageshow เมื่อ event.persisted เป็น true จะช่วยให้การรีเฟรชเกิดขึ้นได้โดยไม่ส่งผลต่อประสิทธิภาพของหน้าเว็บ โปรดตรวจสอบกับผู้ให้บริการโฆษณา แต่นี่คือตัวอย่างวิธีทําด้วยแท็กการเผยแพร่โฆษณาของ Google
หลีกเลี่ยงwindow.openerการอ้างอิง
ในเบราว์เซอร์รุ่นเก่า หากมีการเปิดหน้าเว็บโดยใช้ window.open() จากลิงก์ที่มี target=_blank โดยไม่ได้ระบุ rel="noopener" หน้าที่เปิดจะมีข้อมูลอ้างอิงถึงออบเจ็กต์หน้าต่างของหน้าที่เปิด
นอกจากเป็นความเสี่ยงด้านความปลอดภัยแล้ว หน้าเว็บที่มีการอ้างอิง window.opener ที่ไม่ใช่ค่าว่างจะใส่ลงใน bfcache อย่างปลอดภัยไม่ได้ เนื่องจากอาจทำให้หน้าเว็บที่พยายามเข้าถึงการอ้างอิงดังกล่าวใช้งานไม่ได้
ด้วยเหตุนี้ จึงควรหลีกเลี่ยงการสร้างการอ้างอิง window.opener คุณทำได้โดยใช้ rel="noopener" ทุกครั้งที่เป็นไปได้ (โปรดทราบว่าตอนนี้เบราว์เซอร์ที่ทันสมัยทั้งหมดใช้การตั้งค่านี้เป็นค่าเริ่มต้น) หากเว็บไซต์ของคุณกำหนดให้เปิดหน้าต่างและควบคุมผ่าน window.postMessage() หรืออ้างอิงออบเจ็กต์หน้าต่างโดยตรง ทั้งหน้าต่างที่เปิดและหน้าต่างที่เปิดจะไม่เข้าเกณฑ์สำหรับ bfcache
ปิดการเชื่อมต่อที่เปิดอยู่ก่อนที่ผู้ใช้จะไปยังหน้าอื่น
ดังที่กล่าวไว้ก่อนหน้านี้ เมื่อหน้าเว็บอยู่ใน bfcache ระบบจะหยุดงาน JavaScript ที่กำหนดเวลาไว้ทั้งหมดชั่วคราวและจะกลับมาทำงานต่อเมื่อนำหน้าเว็บออกจากแคช
หากงาน JavaScript ที่กำหนดเวลาไว้เหล่านี้เข้าถึงเฉพาะ DOM API หรือ API อื่นๆ ที่แยกไว้สำหรับหน้าปัจจุบันเท่านั้น การหยุดงานเหล่านี้ชั่วคราวขณะที่ผู้ใช้ไม่เห็นหน้าเว็บจะไม่ทำให้เกิดปัญหาใดๆ
อย่างไรก็ตาม หากงานเหล่านี้เชื่อมต่อกับ API ที่เข้าถึงได้จากหน้าอื่นๆ ในต้นทางเดียวกันด้วย (เช่น IndexedDB, Web Locks, WebSockets) ก็อาจเกิดปัญหาได้เนื่องจากการหยุดงานเหล่านี้ชั่วคราวอาจทำให้โค้ดในแท็บอื่นๆ ทำงานไม่ได้
ด้วยเหตุนี้ เบราว์เซอร์บางตัวจึงไม่พยายามใส่หน้าเว็บลงใน bfcache ในสถานการณ์ต่อไปนี้
- หน้าที่มีการเชื่อมต่อ IndexedDB แบบเปิด
- หน้าเว็บที่มี fetch() หรือ XMLHttpRequest ที่กำลังดำเนินการ
- หน้าที่มีการเชื่อมต่อ WebSocket หรือ WebRTC ที่เปิดอยู่
หากหน้าเว็บของคุณใช้ API เหล่านี้ เราขอแนะนำให้ปิดการเชื่อมต่อและนำหรือยกเลิกการเชื่อมต่อ Observer ในระหว่างเหตุการณ์ pagehide หรือ freeze ซึ่งจะช่วยให้เบราว์เซอร์แคชหน้าเว็บได้อย่างปลอดภัยโดยไม่ต้องเสี่ยงต่อการส่งผลกระทบต่อแท็บอื่นๆ ที่เปิดอยู่
จากนั้นหากมีการกู้คืนหน้าเว็บจาก bfcache คุณจะเปิดหรือเชื่อมต่อ API เหล่านั้นอีกครั้งได้ในระหว่างเหตุการณ์ pageshow หรือ resume
ตัวอย่างต่อไปนี้แสดงวิธีตรวจสอบว่าหน้าเว็บที่ใช้ IndexedDB มีสิทธิ์ใช้ bfcache โดยการปิดการเชื่อมต่อที่เปิดอยู่ในเครื่องมือฟังเหตุการณ์ pagehide
let dbPromise;
function openDB() {
if (!dbPromise) {
dbPromise = new Promise((resolve, reject) => {
const req = indexedDB.open('my-db', 1);
req.onupgradeneeded = () => req.result.createObjectStore('keyval');
req.onerror = () => reject(req.error);
req.onsuccess = () => resolve(req.result);
});
}
return dbPromise;
}
// Close the connection to the database when the user leaves.
window.addEventListener('pagehide', () => {
if (dbPromise) {
dbPromise.then(db => db.close());
dbPromise = null;
}
});
// Open the connection when the page is loaded or restored from bfcache.
window.addEventListener('pageshow', () => openDB());
ทดสอบเพื่อให้แน่ใจว่าหน้าเว็บแคชได้
เครื่องมือสำหรับนักพัฒนาเว็บใน Chrome ช่วยคุณทดสอบหน้าเว็บเพื่อให้มั่นใจว่าหน้าเว็บได้รับการเพิ่มประสิทธิภาพสำหรับ bfcache และระบุปัญหาที่อาจทำให้หน้าเว็บไม่มีสิทธิ์
วิธีทดสอบหน้าเว็บ
- ไปที่หน้าเว็บใน Chrome
- ในเครื่องมือสำหรับนักพัฒนาเว็บ ให้ไปที่แอปพลิเคชัน -> แคชย้อนกลับ/ไปข้างหน้า
- คลิกปุ่มเรียกใช้การทดสอบ จากนั้นเครื่องมือสำหรับนักพัฒนาเว็บจะพยายามไปยังหน้าอื่นแล้วกลับมา เพื่อพิจารณาว่ากู้คืนหน้าเว็บจาก bfcache ได้หรือไม่
หากการทดสอบสำเร็จ แผงจะรายงานว่า "กู้คืนจากแคชย้อนหลัง"
หากไม่สำเร็จ แผงจะระบุสาเหตุ หากเหตุผลเป็นสิ่งที่คุณสามารถแก้ไขได้ในฐานะนักพัฒนาแอป แผงจะทำเครื่องหมายเป็นดำเนินการได้
ในตัวอย่างนี้ การใช้ Listener เหตุการณ์ unload ทำให้หน้าเว็บไม่มีสิทธิ์ใช้ bfcache คุณแก้ไขปัญหานี้ได้โดยเปลี่ยนจาก unload ไปใช้ pagehide ดังนี้
window.addEventListener('pagehide', ...);
window.addEventListener('unload', ...);
นอกจากนี้ Lighthouse 10.0 ยังเพิ่มการตรวจสอบ bfcache ซึ่งจะทำการทดสอบที่คล้ายกัน ดูข้อมูลเพิ่มเติมได้ที่เอกสารของ bfcache audit
bfcache ส่งผลต่อการวัดผลวิเคราะห์และประสิทธิภาพอย่างไร
หากใช้เครื่องมือวิเคราะห์เพื่อวัดการเข้าชมเว็บไซต์ คุณอาจสังเกตเห็นว่าจำนวนการดูหน้าเว็บทั้งหมดที่รายงานลดลงเนื่องจาก Chrome เปิดใช้ bfcache สำหรับผู้ใช้จำนวนมากขึ้น
ในความเป็นจริง คุณอาจรายงานการดูหน้าเว็บจากเบราว์เซอร์อื่นๆ ที่ใช้ bfcache ต่ำกว่าความเป็นจริงอยู่แล้ว เนื่องจากไลบรารีการวิเคราะห์ยอดนิยมหลายรายการไม่ได้วัดการคืนค่า bfcache เป็นการดูหน้าเว็บใหม่
หากต้องการรวมการคืนค่า bfcache ไว้ในจํานวนการดูหน้าเว็บ ให้ตั้งค่า Listener สําหรับเหตุการณ์ pageshow และตรวจสอบพร็อพเพอร์ตี้ persisted
ตัวอย่างต่อไปนี้แสดงวิธีทําใน Google Analytics เครื่องมือวิเคราะห์อื่นๆ น่าจะใช้ตรรกะที่คล้ายกัน
// Send a pageview when the page is first loaded.
gtag('event', 'page_view');
window.addEventListener('pageshow', (event) => {
// Send another pageview if the page is restored from bfcache.
if (event.persisted) {
gtag('event', 'page_view');
}
});
วัดอัตราส่วนการเข้าชม bfcache
นอกจากนี้ คุณอาจต้องการวัดว่ามีการใช้ bfcache หรือไม่ เพื่อช่วยระบุหน้าเว็บที่ไม่ได้ใช้ bfcache ซึ่งทำได้โดยการวัดประเภทการนำทางสำหรับการโหลดหน้าเว็บ ดังนี้
// Send a navigation_type when the page is first loaded.
gtag('event', 'page_view', {
'navigation_type': performance.getEntriesByType('navigation')[0].type;
});
window.addEventListener('pageshow', (event) => {
if (event.persisted) {
// Send another pageview if the page is restored from bfcache.
gtag('event', 'page_view', {
'navigation_type': 'back_forward_cache';
});
}
});
คำนวณอัตราการเข้าชม bfcache โดยใช้จำนวนการนำทางback_forwardและการนำทางback_forward_cache
คุณควรทราบว่ามีหลายสถานการณ์ที่การนำทางย้อนกลับ/ไปข้างหน้าจะไม่ใช้ bfcache ซึ่งอยู่นอกเหนือการควบคุมของเจ้าของเว็บไซต์ ซึ่งรวมถึงสถานการณ์ต่อไปนี้
- เมื่อผู้ใช้ออกจากเบราว์เซอร์และเริ่มเบราว์เซอร์อีกครั้ง
- เมื่อผู้ใช้ทำซ้ำแท็บ
- เมื่อผู้ใช้ปิดแท็บและเปิดอีกครั้ง
ในบางกรณี เบราว์เซอร์บางตัวอาจเก็บประเภทการนำทางเดิมไว้ จึงอาจแสดงประเภท back_forward แม้ว่าการนำทางเหล่านี้จะไม่ใช่การนำทางย้อนกลับ/ไปข้างหน้าก็ตาม
แม้จะไม่มีการยกเว้นเหล่านั้น ระบบก็จะทิ้ง bfcache หลังจากผ่านไประยะหนึ่งเพื่อประหยัดหน่วยความจำ
ดังนั้นเจ้าของเว็บไซต์จึงไม่ควรคาดหวังอัตราการเข้าชม bfcache 100% สำหรับการนำทาง back_forward ทั้งหมด อย่างไรก็ตาม การวัดอัตราส่วนขององค์ประกอบเหล่านี้อาจมีประโยชน์ในการระบุหน้าเว็บที่ตัวหน้าเว็บเองป้องกันไม่ให้ใช้ bfcache สำหรับการนำทางย้อนกลับและไปข้างหน้าในสัดส่วนสูง
ทีม Chrome ได้เพิ่ม NotRestoredReasons API เพื่อช่วยแสดงเหตุผลที่หน้าเว็บไม่ได้ใช้ bfcache เพื่อให้นักพัฒนาแอปสามารถปรับปรุงอัตราการเข้าชม bfcache ได้ นอกจากนี้ ทีม Chrome ยังได้เพิ่มประเภทการนำทางลงใน CrUX ทำให้คุณดูจำนวนการนำทางด้วย bfcache ได้แม้ว่าจะไม่ได้วัดด้วยตนเองก็ตาม
การวัดประสิทธิภาพ
bfcache ยังอาจส่งผลเสียต่อเมตริกประสิทธิภาพที่รวบรวมในภาคสนาม โดยเฉพาะเมตริกที่วัดเวลาในการโหลดหน้าเว็บ
เนื่องจากการไปยังส่วนต่างๆ ของ bfcache จะคืนค่าหน้าเว็บที่มีอยู่แทนที่จะเริ่มการโหลดหน้าเว็บใหม่ จำนวนการโหลดหน้าเว็บทั้งหมดที่รวบรวมไว้จึงจะลดลงเมื่อเปิดใช้ bfcache แต่สิ่งที่สำคัญคือการโหลดหน้าเว็บที่ถูกแทนที่ด้วยการคืนค่า bfcache น่าจะเป็นการโหลดหน้าเว็บที่เร็วที่สุดในชุดข้อมูล เนื่องจากการไปยังส่วนต่างๆ แบบย้อนกลับและไปข้างหน้าถือเป็นการเข้าชมซ้ำ และโดยทั่วไปการโหลดหน้าเว็บซ้ำจะเร็วกว่าการโหลดหน้าเว็บจากผู้เข้าชมครั้งแรก (เนื่องจากการแคช HTTP ดังที่กล่าวไว้ก่อนหน้านี้)
ผลลัพธ์คือการโหลดหน้าเว็บอย่างรวดเร็วในชุดข้อมูลของคุณจะลดลง ซึ่งอาจทำให้การกระจายช้าลง แม้ว่าประสิทธิภาพที่ผู้ใช้ได้รับอาจดีขึ้นก็ตาม
การจัดการกับปัญหานี้ทำได้หลายวิธี วิธีหนึ่งคือการใส่คำอธิบายประกอบเมตริกการโหลดหน้าเว็บทั้งหมดด้วยประเภทการนำทางที่เกี่ยวข้อง ได้แก่ navigate, reload, back_forward หรือ prerender ซึ่งจะช่วยให้คุณตรวจสอบประสิทธิภาพภายในประเภทการนําทางเหล่านี้ต่อไปได้ แม้ว่าการกระจายโดยรวมจะเบี่ยงเบนไปในทางลบก็ตาม เราขอแนะนำแนวทางนี้สำหรับเมตริกการโหลดหน้าเว็บที่ไม่เน้นผู้ใช้ เช่น เวลาในการตอบสนองแรก (TTFB)
สําหรับเมตริกที่เน้นผู้ใช้เป็นหลัก เช่น Core Web Vitals ตัวเลือกที่ดีกว่าคือการรายงานค่าที่แสดงถึงประสบการณ์ของผู้ใช้ได้อย่างแม่นยำมากขึ้น
ผลกระทบต่อ Core Web Vitals
Core Web Vitals จะวัดประสบการณ์ของผู้ใช้ในหน้าเว็บในมิติต่างๆ (ความเร็วในการโหลด การโต้ตอบ ความเสถียรของภาพ) และเนื่องจากผู้ใช้จะได้รับประสบการณ์การคืนค่า bfcache เป็นการไปยังหน้าที่เร็วกว่าการโหลดหน้าเว็บแบบเต็ม จึงเป็นสิ่งสำคัญที่เมตริก Core Web Vitals จะต้องแสดงให้เห็นถึงเรื่องนี้ ท้ายที่สุดแล้ว ผู้ใช้ไม่ได้สนใจว่ามีการเปิดใช้ bfcache หรือไม่ แต่สนใจเพียงว่าการนำทางนั้นรวดเร็ว
เครื่องมือที่รวบรวมและรายงานเมตริก Core Web Vitals เช่น รายงานประสบการณ์ของผู้ใช้ Chrome จะถือว่าการคืนค่า bfcache เป็นการเข้าชมหน้าเว็บแยกต่างหากในชุดข้อมูล แม้ว่าจะไม่มี API ประสิทธิภาพของเว็บโดยเฉพาะสําหรับการวัดเมตริกเหล่านี้หลังจากที่ bfcache คืนค่า แต่คุณก็ประมาณค่าได้โดยใช้ Web API ที่มีอยู่
- สำหรับ Largest Contentful Paint (LCP) ให้ใช้เดลต้าระหว่างการประทับเวลาของเหตุการณ์
pageshowกับการประทับเวลาของเฟรมที่วาดถัดไป เนื่องจากองค์ประกอบทั้งหมดในเฟรมจะได้รับการวาดพร้อมกัน ในกรณีของการกู้คืน bfcache ค่า LCP และ FCP จะเหมือนกัน - สำหรับ Interaction to Next Paint (INP) ให้ใช้ Performance Observer ที่มีอยู่ต่อไป แต่รีเซ็ตค่า INP ปัจจุบันเป็น 0
- สําหรับ Cumulative Layout Shift (CLS) ให้ใช้ Performance Observer ที่มีอยู่ต่อไป แต่รีเซ็ตค่า CLS ปัจจุบันเป็น 0
ดูรายละเอียดเพิ่มเติมเกี่ยวกับวิธีที่ bfcache ส่งผลต่อเมตริกแต่ละรายการได้ที่หน้าคู่มือเมตริกของ Core Web Vitals แต่ละรายการ ดูตัวอย่างเฉพาะวิธีติดตั้งใช้งานเมตริกเหล่านี้ในเวอร์ชัน bfcache ได้ที่คำขอเปลี่ยนแปลงที่เพิ่มเมตริกลงในไลบรารี JS ของ web-vitals
ไลบรารี JavaScript web-vitals รองรับการคืนค่า bfcache ในเมตริกที่รายงาน
แหล่งข้อมูลเพิ่มเติม
- การแคชของ Firefox (bfcache ใน Firefox)
- แคชหน้าเว็บ (bfcache ใน Safari)
- Back-Forward Cache: ลักษณะการทำงานที่เปิดเผยต่อเว็บ (ความแตกต่างของ bfcache ในเบราว์เซอร์ต่างๆ)
- เครื่องมือทดสอบ bfcache (ทดสอบว่า API และเหตุการณ์ต่างๆ ส่งผลต่อ bfcache ในเบราว์เซอร์อย่างไร)
- ตัวเปลี่ยนเกมด้านประสิทธิภาพ: แคชย้อนกลับ/ไปข้างหน้าของเบราว์เซอร์ (กรณีศึกษาจาก Smashing Magazine ที่แสดงการปรับปรุง Core Web Vitals อย่างมากด้วยการเปิดใช้ bfcache)