Back-Forward Cache

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

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

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

bfcache รองรับทั้ง Firefox และ Safari มาหลายปีแล้วทั้งในเดสก์ท็อปและอุปกรณ์เคลื่อนที่

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

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

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

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

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 แต่นั่นหมายความว่าเบราว์เซอร์intendsให้แคชหน้านี้เท่านั้น แต่อาจยังคงต้องทิ้งโดเมนดังกล่าวด้วยเหตุผลหลายประการซึ่งได้อธิบายไว้ภายหลัง

เพิ่มประสิทธิภาพหน้าเว็บสำหรับ bfcache

หน้าเว็บบางหน้าไม่ได้ถูกจัดเก็บไว้ใน bfcache และแม้ว่าระบบจะจัดเก็บหน้าใดหน้าหนึ่งไว้ในที่ดังกล่าว หน้าเว็บก็จะไม่อยู่ในนั้นต่อไปอย่างไม่มีกำหนด นักพัฒนาซอฟต์แวร์จําเป็นต้องทําความเข้าใจว่าอะไรทําให้หน้าเว็บมีสิทธิ์ (และไม่มีสิทธิ์) สําหรับ bfcache เพื่อเพิ่มอัตรา Hit สูงสุด

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

ไม่ใช้กิจกรรม unload

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

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

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

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

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

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

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

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

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

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

Permission-Policy: unload()

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

เพิ่ม Listener beforeunload อย่างมีเงื่อนไข

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

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

ไม่ควรทำ
window.addEventListener('beforeunload', (event) => {
  if (pageHasUnsavedChanges()) {
    event.preventDefault();
    return event.returnValue = 'Are you sure you want to exit?';
  }
});
โค้ดนี้จะเพิ่ม Listener 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);
});
โค้ดนี้จะเพิ่ม Listener beforeunload เมื่อจำเป็นเท่านั้น (และนำออกเมื่อไม่จำเป็น)

ลดการใช้ Cache-Control: no-store

Cache-Control: no-store เป็นเว็บเซิร์ฟเวอร์ส่วนหัว HTTP ที่ตั้งค่าการตอบกลับที่สั่งเบราว์เซอร์ไม่ให้จัดเก็บการตอบกลับไว้ในแคช HTTP ใดๆ ได้ ซึ่งใช้สำหรับทรัพยากรที่มีข้อมูลผู้ใช้ที่ละเอียดอ่อน เช่น หน้าเว็บที่อยู่หลังการเข้าสู่ระบบ

แม้ว่า bfcache จะไม่ใช่แคช HTTP แต่ในอดีต เมื่อมีการตั้งค่า Cache-Control: no-store บนทรัพยากรของหน้าเว็บเอง (ตรงข้ามกับทรัพยากรย่อย) เบราว์เซอร์เลือกที่จะไม่จัดเก็บหน้าใน bfcache เรากำลังดำเนินการเปลี่ยนแปลงลักษณะการทำงานนี้สำหรับ Chrome ในลักษณะที่รักษาความเป็นส่วนตัว แต่ ณ ปัจจุบัน หน้าเว็บใดก็ตามที่ใช้ Cache-Control: no-store จะไม่มีสิทธิ์ใช้ bfcache

เนื่องจาก 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 ในกรณีต่อไปนี้

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

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

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

หากการทดสอบสำเร็จ แผงจะรายงานว่า "กู้คืนจาก Back-Forward Cache"

เครื่องมือสำหรับนักพัฒนาเว็บที่รายงานว่าหน้ากู้คืนจาก bfcache สำเร็จแล้ว
หน้าที่ได้รับการกู้คืนเรียบร้อยแล้ว

หากไม่สำเร็จ แผงจะแสดงสาเหตุ หากเหตุผลเป็นสิ่งที่คุณจัดการได้ในฐานะนักพัฒนาซอฟต์แวร์ แผงจะทําเครื่องหมายว่าดําเนินการได้

การรายงานเครื่องมือสำหรับนักพัฒนาเว็บไม่สามารถกู้คืนหน้าจาก bfcache ได้
การทดสอบ bfcache ไม่สำเร็จซึ่งมีผลลัพธ์ที่ดำเนินการได้

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

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

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

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');
  }
});

วัดอัตรา Hit ของ 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 หลังจากช่วงเวลาหนึ่งเพื่อประหยัดหน่วยความจำ

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

ทีม Chrome ได้เพิ่ม NotRestoredReasons API เพื่อแสดงเหตุผลที่หน้าเว็บไม่ใช้ bfcache เพื่อให้นักพัฒนาซอฟต์แวร์ปรับปรุงอัตราการค้นพบ 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 แล้ว แต่คุณก็อาจประมาณค่าของเมตริกโดยใช้ 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 ในเมตริกที่รายงาน

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