Back-Forward Cache

Back-Forward Cache (หรือ bfcache) คือการเพิ่มประสิทธิภาพเบราว์เซอร์ที่ช่วยให้ไปยังส่วนต่างๆ แบบย้อนกลับและไปข้างหน้าได้ทันที ฟีเจอร์นี้ช่วยปรับปรุงประสบการณ์การท่องเว็บได้อย่างมาก โดยเฉพาะสำหรับผู้ใช้ที่มีเครือข่ายหรืออุปกรณ์ที่ช้า

ในฐานะนักพัฒนาเว็บ คุณจําเป็นต้องเข้าใจวิธีเพิ่มประสิทธิภาพหน้าเว็บสําหรับ bfcache เพื่อให้ผู้ใช้ได้รับประโยชน์

ความเข้ากันได้กับเบราว์เซอร์

เบราว์เซอร์หลักๆ ทั้งหมดมี bfcache ซึ่งรวมถึง Chrome ตั้งแต่เวอร์ชัน 96, Firefox และ Safari

ข้อมูลเบื้องต้นเกี่ยวกับ bfcache

เมื่อใช้แคช "ย้อนกลับ/ไปข้างหน้า" (bfcache) เราจะเลื่อนการทำลายและหยุดการเรียกใช้ JS ชั่วคราวแทนที่จะทำลายหน้าเว็บเมื่อผู้ใช้ไปยังส่วนอื่น หากผู้ใช้กลับไปในเร็วๆ นี้ เราจะทำให้หน้านั้นแสดงอีกครั้งและยกเลิกการหยุดการดำเนินการ JS ชั่วคราว ซึ่งส่งผลให้ผู้ใช้ไปยังส่วนต่างๆ ของหน้าเว็บได้เกือบจะทันที

คุณเคยเข้าชมเว็บไซต์และคลิกลิงก์เพื่อไปยังหน้าอื่นกี่ครั้งแล้ว แต่พบว่าไม่ใช่สิ่งที่ต้องการและคลิกปุ่มย้อนกลับ ในช่วงเวลาดังกล่าว bfcache จะทําให้หน้าก่อนหน้าโหลดได้เร็วขึ้นอย่างมาก ดังนี้

ไม่ได้เปิดใช้ bfcache ระบบจะเริ่มคําขอใหม่เพื่อโหลดหน้าก่อนหน้า และเบราว์เซอร์อาจต้องดาวน์โหลด แยกวิเคราะห์ และเรียกใช้ทรัพยากรบางส่วน (หรือทั้งหมด) ที่เพิ่งดาวน์โหลดมาอีกครั้ง ทั้งนี้ขึ้นอยู่กับว่าหน้าเว็บได้รับการเพิ่มประสิทธิภาพสำหรับการเข้าชมซ้ำมากน้อยเพียงใด
เมื่อเปิดใช้ 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 ตัวอย่างเช่น หากคุณไปยังหน้าอื่นภายใน iframe แล้วกลับไป เบราว์เซอร์จะ "กลับ" ภายใน iframe แทนที่จะกลับในเฟรมหลัก แต่การไปยังส่วนต่างๆ กลับภายใน iframe จะไม่ใช้ bfcache

นอกจากนี้ ระบบยังบล็อกเฟรมหลักไม่ให้ใช้ bfcache ได้หาก iframe ที่ฝังใช้ API ที่บล็อกการดำเนินการนี้ คุณใช้นโยบายสิทธิ์ที่ตั้งค่าไว้ในเฟรมหลักหรือใช้แอตทริบิวต์ sandbox เพื่อหลีกเลี่ยงปัญหานี้ได้

แอป bfcache และแอปหน้าเดียว (SPA)

เนื่องจาก bfcache ทํางานกับการนําทางที่จัดการโดยเบราว์เซอร์ จึงใช้ไม่ได้กับ "การนําทางแบบซอฟต์" ภายในแอปหน้าเว็บเดียว (SPA) อย่างไรก็ตาม bfcache จะยังคงมีประโยชน์เมื่อกลับไปใช้ SPA แทนที่จะทำการเริ่มต้นแอปนั้นใหม่ทั้งหมดตั้งแต่ต้น

API สําหรับสังเกต bfcache

แม้ว่า 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 ได้ แต่หากต้องการวัดอัตรา Hit ของ 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 เพื่อเพิ่มอัตรา Hit ของแคชให้สูงสุด

ส่วนต่อไปนี้จะสรุปแนวทางปฏิบัติที่ดีที่สุดเพื่อให้เบราว์เซอร์มีโอกาสแคชหน้าเว็บมากที่สุด

ไม่ใช้เหตุการณ์ unload

วิธีที่สำคัญที่สุดในการเพิ่มประสิทธิภาพสำหรับ bfcache ในเบราว์เซอร์ทั้งหมดคือการไม่ใช้เหตุการณ์ unload ได้เลย!

เหตุการณ์ unload เป็นปัญหาสําหรับเบราว์เซอร์เนื่องจากอยู่ก่อน bfcache และหน้าเว็บจํานวนมากในอินเทอร์เน็ตทํางานภายใต้การคาดการณ์ (ที่สมเหตุสมผล) ว่าหน้าเว็บจะไม่มีอยู่อีกต่อไปหลังจากเหตุการณ์ unload เริ่มทํางาน ปัญหานี้เกิดขึ้นเนื่องจากหน้าเว็บจํานวนมากยังสร้างขึ้นโดยคํานึงว่าเหตุการณ์ unload จะทํางานทุกครั้งที่ผู้ใช้ไปยังหน้าอื่น ซึ่งไม่ถูกต้องแล้ว (และไม่ถูกต้องมาเป็นเวลานาน)

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

ในเดสก์ท็อป Chrome และ Firefox เลือกที่จะทําให้หน้าเว็บไม่มีสิทธิ์ใช้ bfcache หากเพิ่มunload Listener ซึ่งเสี่ยงน้อยกว่า แต่ก็ทำให้หน้าเว็บจํานวนมากไม่มีสิทธิ์ใช้ Safari จะพยายามแคชหน้าเว็บบางหน้าด้วย unload event listener แต่จะไม่เรียกใช้เหตุการณ์ unload เมื่อผู้ใช้ไปยังส่วนอื่นเพื่อลดโอกาสที่ระบบจะขัดข้อง ซึ่งทำให้เหตุการณ์ไม่น่าเชื่อถือมากนัก

ในอุปกรณ์เคลื่อนที่ Chrome และ Safari จะพยายามแคชหน้าเว็บที่มี Listener เหตุการณ์ unload เนื่องจากความเสี่ยงในการหยุดทำงานนั้นต่ำกว่าเพราะเหตุการณ์ unload ไม่น่าเชื่อถืออย่างมากมาโดยตลอดในอุปกรณ์เคลื่อนที่ Firefox จะถือว่าหน้าเว็บที่ใช้ unload ไม่มีสิทธิ์ใช้ bfcache ยกเว้นใน iOS ซึ่งกำหนดให้เบราว์เซอร์ทุกตัวต้องใช้เครื่องมือแสดงผล WebKit ดังนั้นจึงทํางานเหมือน Safari

ใช้เหตุการณ์ pagehide แทนเหตุการณ์ unload เหตุการณ์ pagehide จะทริกเกอร์ในทุกกรณีที่เหตุการณ์ unload ทริกเกอร์ และยังทริกเกอร์เมื่อมีการใส่หน้าเว็บลงใน bfcache ด้วย

ความจริงแล้ว Lighthouse มีการตรวจสอบ no-unload-listeners ซึ่งจะเตือนนักพัฒนาซอฟต์แวร์หาก JavaScript ในหน้าเว็บ (รวมถึงจากไลบรารีของบุคคลที่สาม) เพิ่ม unload event listener

Chrome กำลังพิจารณาที่จะเลิกใช้งานเหตุการณ์ unload เนื่องจากความไม่น่าเชื่อถือและผลกระทบด้านประสิทธิภาพของ bfcache

ใช้นโยบายสิทธิ์เพื่อป้องกันไม่ให้ใช้ตัวแฮนเดิลการยกเลิกการโหลดในหน้าเว็บ

เว็บไซต์ที่ไม่ได้ใช้ตัวแฮนเดิลเหตุการณ์ unload สามารถตรวจสอบได้ว่าไม่มีการเพิ่มตัวแฮนเดิลเหล่านี้โดยใช้นโยบายสิทธิ์

Permission-Policy: unload=()

นอกจากนี้ ยังป้องกันไม่ให้บุคคลที่สามหรือส่วนขยายทําให้เว็บไซต์ช้าลงด้วยการเพิ่มตัวแฮนเดิลการยกเลิกการโหลดและทําให้เว็บไซต์ไม่มีสิทธิ์ใช้ bfcache

เพิ่มผู้ฟังตามเงื่อนไขเพียง beforeunload รายเท่านั้น

เหตุการณ์ beforeunload จะไม่ทำให้หน้าเว็บของคุณไม่มีสิทธิ์ใช้ bfcache ในเบราว์เซอร์สมัยใหม่ bfcache แต่ก่อนหน้านี้ดำเนินการแล้วและยังคงไม่น่าเชื่อถือ ดังนั้นให้หลีกเลี่ยงการใช้เว้นแต่จะจำเป็นจริงๆ

อย่างไรก็ตาม beforeunload มีการใช้งานที่ถูกต้องตามกฎหมาย ซึ่งแตกต่างจากเหตุการณ์ unload เช่น เมื่อต้องการเตือนผู้ใช้ว่ามีการเปลี่ยนแปลงที่ยังไม่ได้บันทึกซึ่งจะหายไปหากออกจากหน้า ในกรณีนี้ เราขอแนะนําให้เพิ่มbeforeunload Listeners เฉพาะเมื่อผู้ใช้มีการเปลี่ยนแปลงที่ไม่ได้บันทึกไว้ แล้วนําออกทันทีหลังจากบันทึกการเปลี่ยนแปลงที่ไม่ได้บันทึกไว้

ไม่ควรทำ
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 listener เฉพาะเมื่อจําเป็นเท่านั้น (และนําออกเมื่อไม่จําเป็น)

ลดการใช้ 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 ที่ไม่ใช่ค่า Null ยังไม่สามารถใส่ลงใน bfcache ได้เนื่องจากอาจทำให้หน้าเว็บที่พยายามเข้าถึงหน้านั้นใช้งานไม่ได้

ดังนั้น เราขอแนะนำให้หลีกเลี่ยงการสร้างการอ้างอิง window.opener ซึ่งทำได้โดยใช้ rel="noopener" เมื่อใดก็ตามที่เป็นไปได้ (โปรดทราบว่าตอนนี้เป็นค่าเริ่มต้นในเบราว์เซอร์สมัยใหม่ทั้งหมด) หากเว็บไซต์ของคุณกำหนดให้เปิดหน้าต่างและควบคุมผ่าน window.postMessage() หรืออ้างอิงออบเจ็กต์หน้าต่างโดยตรง ทั้งหน้าต่างที่เปิดอยู่และผู้เปิดจะไม่มีสิทธิ์ใช้ bfcache

ปิดการเชื่อมต่อที่เปิดอยู่ก่อนที่ผู้ใช้จะออกไป

ดังที่ได้กล่าวไว้ก่อนหน้านี้ เมื่อระบบเก็บหน้าเว็บไว้ใน bfcache ระบบจะหยุดงาน JavaScript ที่กำหนดเวลาไว้ทั้งหมดไว้ชั่วคราวและดําเนินการต่อเมื่อนำหน้าเว็บออกจากแคช

หากงาน JavaScript ที่ตั้งเวลาไว้เหล่านี้เข้าถึงเฉพาะ DOM API หรือ API อื่นๆ ที่แยกไว้สำหรับหน้าปัจจุบันเท่านั้น การหยุดงานเหล่านี้ชั่วคราวขณะที่ผู้ใช้ไม่เห็นหน้าเว็บจะไม่ก่อให้เกิดปัญหาใดๆ

อย่างไรก็ตาม หากงานเหล่านี้เชื่อมต่อกับ API ที่เข้าถึงได้จากหน้าอื่นๆ ในต้นทางเดียวกัน (เช่น IndexedDB, Web Lock, WebSocket) การดำเนินการนี้อาจทำให้เกิดปัญหาได้ เนื่องจากการหยุดงานเหล่านี้ชั่วคราวอาจทำให้โค้ดในแท็บอื่นๆ ไม่ทำงาน

ด้วยเหตุนี้ เบราว์เซอร์บางรุ่นจะไม่พยายามใส่หน้าเว็บลงใน bfcache ในสถานการณ์ต่อไปนี้

หากหน้าเว็บของคุณใช้ API เหล่านี้ เราขอแนะนําอย่างยิ่งให้ปิดการเชื่อมต่อและนําผู้สังเกตการณ์ออกหรือยกเลิกการเชื่อมต่อระหว่างเหตุการณ์ pagehide หรือ freeze วิธีนี้จะช่วยให้เบราว์เซอร์สามารถแคชหน้าเว็บได้อย่างปลอดภัยโดยไม่ส่งผลกระทบต่อแท็บอื่นๆ ที่เปิดอยู่

จากนั้น หากมีการคืนค่าหน้าจาก bfcache คุณสามารถเปิดหรือเชื่อมต่อกับ API เหล่านั้นอีกครั้งระหว่างเหตุการณ์ pageshow หรือ resume

ตัวอย่างต่อไปนี้แสดงวิธีตรวจสอบว่าหน้าที่ใช้ IndexedDB มีสิทธิ์ใช้ bfcache ด้วยการปิดการเชื่อมต่อแบบเปิดใน Listener เหตุการณ์ 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 DevTools ช่วยให้คุณทดสอบหน้าเว็บเพื่อให้แน่ใจว่าหน้าเว็บได้รับการเพิ่มประสิทธิภาพสำหรับ bfcache และระบุปัญหาที่อาจทำให้หน้าเว็บไม่มีสิทธิ์

วิธีทดสอบหน้าเว็บ

  1. ไปที่หน้าเว็บใน Chrome
  2. ในเครื่องมือสำหรับนักพัฒนาเว็บ ให้ไปที่แอปพลิเคชัน -> แคชการย้อนกลับและเดินหน้า
  3. คลิกปุ่มเรียกใช้การทดสอบ จากนั้นเครื่องมือสําหรับนักพัฒนาเว็บจะพยายามไปยังส่วนอื่นแล้วกลับมาเพื่อดูว่ากู้คืนหน้าเว็บจาก bfcache ได้หรือไม่
แผงแคชย้อนหลังในเครื่องมือสำหรับนักพัฒนาเว็บ
แผงแคชย้อนหลังในเครื่องมือสำหรับนักพัฒนาเว็บ

หากการทดสอบสําเร็จ แผงจะแสดงข้อความ "กู้คืนจากแคชย้อนกลับ"

เครื่องมือสําหรับนักพัฒนาซอฟต์แวร์รายงานว่ากู้คืนหน้าเว็บจาก bfcache เรียบร้อยแล้ว
หน้าเว็บที่กู้คืนสําเร็จ

หากดำเนินการไม่สำเร็จ แผงจะระบุสาเหตุ หากเหตุผลเป็นปัญหาที่คุณแก้ไขได้ในฐานะนักพัฒนาแอป แผงจะระบุว่าดำเนินการได้

เครื่องมือสำหรับนักพัฒนาเว็บรายงานว่าคืนค่าหน้าเว็บจาก bfcache ไม่สำเร็จ
การทดสอบ bfcache ล้มเหลวพร้อมผลลัพธ์ที่นําไปใช้ได้

ในตัวอย่างนี้ การใช้ unload Listener เหตุการณ์ทําให้หน้าเว็บไม่มีสิทธิ์ใช้ bfcache คุณสามารถแก้ไขปัญหานี้ได้โดยเปลี่ยนจาก unload ไปใช้ pagehide โดยทำดังนี้

ควรทำ
window.addEventListener('pagehide', ...);
ไม่ควรทำ
window.addEventListener('unload', ...);

Lighthouse 10.0 ยังเพิ่มการตรวจสอบ bfcache ด้วย ซึ่งทำการทดสอบที่คล้ายกัน ดูข้อมูลเพิ่มเติมได้ที่เอกสารของการตรวจสอบ bfcache

ผลกระทบของ bfcache ต่อข้อมูลวิเคราะห์และการวัดประสิทธิภาพ

หากคุณใช้เครื่องมือวิเคราะห์เพื่อวัดการเข้าชมเว็บไซต์ คุณอาจเห็นว่าจำนวนการดูหน้าเว็บทั้งหมดที่รายงานลดลงเมื่อ Chrome เปิดใช้ bfcache ให้กับผู้ใช้จำนวนมากขึ้น

อันที่จริง คุณอาจรายงานการดูหน้าเว็บจากเบราว์เซอร์อื่นๆ ที่ใช้ bfcache ต่ำกว่าความเป็นจริงอยู่แล้ว เนื่องจากคลังข้อมูลวิเคราะห์ยอดนิยมจํานวนมากไม่ได้วัดการกู้คืน bfcache เป็นยอดดูหน้าเว็บใหม่

หากต้องการรวมการกู้คืน bfcache ไว้ในจํานวนการดูหน้าเว็บ ให้ตั้งค่า Listeners สําหรับเหตุการณ์ 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';
   
});
 
}
});

คํานวณอัตรา Hit ของ bfcache โดยใช้จํานวนการนําทาง back_forward และการนําทาง back_forward_cache

โปรดทราบว่ามีบางกรณีที่อยู่นอกเหนือการควบคุมของเจ้าของเว็บไซต์ ซึ่งการนําทางย้อนกลับ/ไปข้างหน้าจะไม่ใช้ bfcache ซึ่งรวมถึงกรณีต่อไปนี้

  • เมื่อผู้ใช้ออกจากเบราว์เซอร์และเริ่มอีกครั้ง
  • เมื่อผู้ใช้ทำซ้ำแท็บ
  • เมื่อผู้ใช้ปิดแท็บแล้วเปิดอีกครั้ง

ในบางกรณีเหล่านี้ ประเภทการนำทางเดิมอาจยังคงอยู่ในบางเบราว์เซอร์ และอาจแสดงประเภท back_forward แม้ว่ารายการเหล่านี้จะไม่ได้เป็นการนำทางกลับ/ไปข้างหน้าก็ตาม

แม้ว่าจะไม่มีการยกเว้นดังกล่าว แต่ bfcache จะถูกทิ้งหลังจากผ่านไประยะหนึ่งเพื่อประหยัดหน่วยความจำ

ดังนั้นเจ้าของเว็บไซต์จึงไม่ควรคาดหวังอัตราการเกิด bfcache 100% สำหรับการนำทางทั้งหมดของ back_forward อย่างไรก็ตาม การวัดอัตราส่วนอาจเป็นประโยชน์ในการระบุหน้าที่หน้าเว็บป้องกันไม่ให้ใช้ bfcache สำหรับการนำทางย้อนกลับและไปข้างหน้าในสัดส่วนที่สูง

ทีม Chrome ได้เพิ่ม NotRestoredReasons API เพื่อช่วยแสดงสาเหตุที่หน้าเว็บไม่ใช้ bfcache เพื่อให้นักพัฒนาซอฟต์แวร์ปรับปรุงอัตรา Hit ของ bfcache ได้ ทีม Chrome ยังเพิ่มประเภทการนําทางลงใน CrUX เพื่อให้คุณเห็นจํานวนการนําทางใน bfcache ได้โดยไม่ต้องวัดด้วยตนเอง

การวัดประสิทธิภาพ

bfcache ยังส่งผลเสียต่อเมตริกประสิทธิภาพที่รวบรวมในภาคสนาม โดยเฉพาะเมตริกที่วัดเวลาในการโหลดหน้าเว็บ

เนื่องจากการนำทาง bfcache จะกู้คืนหน้าเว็บที่มีอยู่แทนที่จะเริ่มต้นการโหลดหน้าเว็บใหม่ จำนวนการโหลดหน้าเว็บทั้งหมดที่รวบรวมจะลดลงเมื่อเปิดใช้ bfcache แต่สิ่งสําคัญคือหน้าเว็บที่โหลดซึ่งถูกแทนที่ด้วยการกู้คืน bfcache น่าจะเป็นหน้าเว็บที่โหลดเร็วที่สุดในชุดข้อมูล เนื่องจากตามคําจํากัดความแล้ว การไปยังส่วนต่างๆ แบบย้อนกลับและแบบไปข้างหน้าเป็นการเข้าชมซ้ำ และโดยทั่วไปการโหลดหน้าเว็บซ้ำจะเร็วกว่าการโหลดหน้าเว็บจากผู้เข้าชมครั้งแรก (เนื่องจากการแคช HTTP ตามที่กล่าวไว้ก่อนหน้านี้)

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

การแก้ปัญหานี้ทำได้หลายวิธี วิธีหนึ่งคือการกำกับเนื้อหาเมตริกการโหลดหน้าเว็บทั้งหมดด้วยประเภทการนําทางที่เกี่ยวข้อง ซึ่งได้แก่ navigate, reload, back_forward หรือ prerender ซึ่งจะช่วยให้คุณตรวจสอบประสิทธิภาพในการนําทางประเภทเหล่านี้ได้ต่อไป แม้ว่าการแจกแจงโดยรวมจะเบี่ยงเบนไปในเชิงลบ เราขอแนะนําแนวทางนี้สําหรับเมตริกการโหลดหน้าเว็บที่ไม่ได้เน้นผู้ใช้ เช่น Time To First Byte (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) ให้ใช้เครื่องมือสังเกตประสิทธิภาพที่มีอยู่ต่อไป แต่รีเซ็ตค่า INP ปัจจุบันเป็น 0
  • สำหรับ Cumulative Layout Shift (CLS) ให้ใช้ Performance Observer ที่มีอยู่ต่อไป แต่รีเซ็ตค่า CLS ปัจจุบันเป็น 0

ดูรายละเอียดเพิ่มเติมเกี่ยวกับวิธีที่ bfcache ส่งผลต่อเมตริกแต่ละรายการได้ที่หน้าคำแนะนำเมตริกของ Core Web Vitals ดูตัวอย่างที่เฉพาะเจาะจงของวิธีใช้เมตริกเหล่านี้ในเวอร์ชัน bfcache ได้ที่ PR การเพิ่มเมตริกเหล่านี้ลงในคลัง JS ของ Web Vitals

ไลบรารี JavaScript ของ web-vitals รองรับการกู้คืน bfcache ในเมตริกที่รายงาน

แหล่งข้อมูลเพิ่มเติม