bfcache 是什麼?為什麼 unload 會讓頁面失去 bfcache 資格
此文章是 FrontendMaster 上的 Advanced Web Development Quiz 課程筆記
問題
Which of the following values will always make your page ineligible for bfcache?
Select all the correct answers.
[1] unload
[2] pagehide
[3] onbeforeunload
[4] pageshow
[5] all of the above
[6] none of the abovebfcache?
bfcache 會把「整個頁面」存在記憶體裡,包含 DOM 與 JavaScript 執行狀態,回到上一頁/下一頁時可以幾乎瞬間還原,不必重建 DOM、重跑 CSS、重發請求。它和 HTTP 快取不同:HTTP 快取存的是回應資料,而 bfcache 存的是整頁快照。進入 bfcache 時瀏覽器會暫停 JS 執行與待處理工作(像計時器、Promise 等),並在還原時再繼續。
unload 對於 bfcache 的影響
unload 是一個被棄用的事件,最初的設計是假設這個事件被觸發的時候,頁面已經不會再被使用了,跟 bfcache 的核心用途相違背,因此多數瀏覽器判斷如果頁面有使用到 unload 事件,就不會使用 bfcache,另外 safari 會嘗試使用 unload 來快取部分網頁,但 Safari 不會在使用者離開時執行 unload 事件,這會讓事件變得非常不可靠。
所以這個事件最好是不要使用,而且我們仍然可以使用 pagehide 事件來取代 unload。
pagehide
pagehide 事件會在網頁卸載或瀏覽器嘗試將網頁放入 bfcache 時觸發,我們可以透過 event.persisted 來判斷目前的頁面是否被存入 bfcache
javascript
window.addEventListener(
'pagehide',
(event) => {
if (event.persisted) {
/* 頁面被存入 bfcache */
}
},
false,
);pageshow
當網頁初次載入,以及任何時候從 bfcache 還原網頁時,pageshow 事件會在 load 事件後立即觸發。此時就可以透過 event.persisted 判斷是不是透過 bfcache 來還原的頁面
javascript
window.addEventListener('pageshow', (event) => {
if (event.persisted) {
/* 這個頁面被從 bfcache 恢復 */
}
});beforeunload
beforeunload 通常是使用於提醒使用者目前仍有未儲存的變更(例如:表單填寫的頁面),當使用者要離開頁面時,這個事件會被觸發,讓使用者確認是否真的要離開。
此事件不會讓網頁在現代瀏覽器中無法使用 bfcache,但先前曾發生這種情況,且仍不穩定,因此除非絕對必要,否則請避免使用。
最佳的使用方法是在確定使用者有未儲存的資料時,監聽該事件,並於使用者沒有未儲存資料時取消監聽事件。
javascript
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);
});答案
[1] unload