Back-Forward Cache

เผยแพร่: 25 พฤษภาคม 2023, อัปเดตล่าสุด: 25 มีนาคม 2025

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

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

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

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

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

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

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

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

ดูวิดีโอนี้เกี่ยวกับ bfcache ที่ใช้งานจริงเพื่อทำความเข้าใจการเพิ่มความเร็วในการไปยังส่วนต่างๆ

การใช้ bfcache ช่วยให้หน้าเว็บโหลดได้เร็วขึ้นมากในระหว่างการไปยังส่วนต่างๆ แบบย้อนกลับและไปข้างหน้า

ในวิดีโอ ตัวอย่างที่มี bfcache จะเร็วกว่าตัวอย่างที่ไม่มี bfcache มาก

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

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

วิธีการทำงานของ "แคช"

"แคช" ที่ bfcache ใช้จะแตกต่างจากแคช HTTP ซึ่งมีบทบาทของตัวเองในการเร่งการไปยังส่วนต่างๆ ซ้ำ bfcache คือภาพรวมของทั้งหน้าในหน่วยความจำ รวมถึงฮีป JavaScript ในขณะที่แคช HTTP จะมีเฉพาะการตอบกลับสำหรับคำขอที่ส่งก่อนหน้านี้ เนื่องจากคำขอทั้งหมดที่จำเป็นในการโหลดหน้าเว็บนั้นแทบจะไม่ได้รับการตอบสนองจากแคช HTTP เลย การเข้าชมซ้ำโดยใช้การคืนค่า bfcache จึงเร็วกว่าการไปยังส่วนต่างๆ ที่ไม่ใช่ bfcache ที่ได้รับการเพิ่มประสิทธิภาพอย่างดีที่สุดเสมอ

การหยุดหน้าชั่วคราวเพื่ออาจเปิดใช้อีกครั้งในภายหลังมีความซับซ้อนในแง่ของวิธีที่ดีที่สุดในการเก็บรักษารหัสที่อยู่ระหว่างดำเนินการ เช่น คุณจะจัดการsetTimeout()การเรียกที่หมดเวลาขณะที่หน้าเว็บอยู่ใน bfcache อย่างไร

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

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

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

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

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

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

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

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

ในเดสก์ท็อป Chrome และ Firefox เลือกที่จะทำให้หน้าเว็บไม่มีสิทธิ์ใช้ bfcache หากเพิ่มunload Listener ซึ่งมีความเสี่ยงน้อยกว่า แต่ก็ทำให้หน้าเว็บจำนวนมากไม่มีสิทธิ์ด้วย 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

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

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

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

Permissions-Policy: unload=()

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

เพิ่มเครื่องฟัง beforeunload รายการแบบมีเงื่อนไขเท่านั้น

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

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

ไม่ควรทำ
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 ดังนั้นหน้าเว็บที่ใช้ 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 ในสถานการณ์ต่อไปนี้

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

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

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

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

เครื่องมือสำหรับนักพัฒนาเว็บรายงานว่ากู้คืนหน้าเว็บจาก bfcache ไม่สำเร็จ
การทดสอบ 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.
// This happens by default just by loading gtag
gtag('config', 'TAG_ID');

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.
// To do this disable the default pageview so you can manually send it
// supplemented with the additional detail.
gtag('config', 'TAG_ID', { send_page_view: false });
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 ในเมตริกที่รายงาน

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