監控 bfcache 阻止原因
PerformanceNavigationTiming.notRestoredReasons 屬性報告了當前文件在導航時被阻止使用 bfcache 的資訊。開發者可以使用這些資訊來識別需要更新才能與 bfcache 相容的頁面,從而提高網站效能。
前進/後退快取(bfcache)
現代瀏覽器為歷史導航提供了一種最佳化功能,稱為前進/後退快取(bfcache)。這使使用者在返回已訪問過的頁面時能獲得即時載入體驗。頁面可能因各種原因被阻止進入 bfcache,或在 bfcache 中被驅逐,其中一些是規範要求的,另一些是瀏覽器實現特有的。
為了能夠監控 bfcache 阻塞原因,PerformanceNavigationTiming 類包含一個 notRestoredReasons 屬性。該屬性返回一個 NotRestoredReasons 物件,其中包含有關頂級幀和文件中所有 <iframe> 的相關資訊。
- bfcache 使用被阻止的原因。
- 詳細資訊,例如幀的
id和name,以幫助識別 HTML 中的<iframe>。
注意: 歷史上,已廢棄的 PerformanceNavigation.type 屬性用於監控 bfcache,開發者透過測試 type 為 "TYPE_BACK_FORWARD" 來獲取 bfcache 命中率的指示。然而,這並未提供任何 bfcache 阻塞的原因或其他資料。今後應使用 notRestoredReasons 屬性來監控 bfcache 阻塞。
記錄 bfcache 阻塞原因
可以使用 PerformanceObserver 獲取持續的 bfcache 阻塞資料,如下所示:
const observer = new PerformanceObserver((list) => {
let perfEntries = list.getEntries();
perfEntries.forEach((navEntry) => {
console.log(navEntry.notRestoredReasons);
});
});
observer.observe({ type: "navigation", buffered: true });
或者,您可以使用合適的方法(例如 Performance.getEntriesByType())獲取歷史 bfcache 阻塞資料。
function returnNRR() {
const navEntries = performance.getEntriesByType("navigation");
for (let i = 0; i < navEntries.length; i++) {
console.log(`Navigation entry ${i}`);
let navEntry = navEntries[i];
console.log(navEntry.notRestoredReasons);
}
}
上面顯示的程式碼片段會將 NotRestoredReasons 物件記錄到控制檯。這些物件具有以下結構,代表了頂級幀的阻塞狀態:
{
"children": [],
"id": null,
"name": null,
"reasons": [{ "reason": "unload-listener" }],
"src": "",
"url": "example.com"
}
屬性如下:
children只讀 實驗性-
一個
NotRestoredReasons物件陣列,每個物件對應當前文件中嵌入的子<iframe>,其中可能包含與子幀相關的頂級幀被阻止的原因。每個物件都具有與父物件相同的結構——這樣,物件中可以遞迴表示任意數量的嵌入<iframe>級別。如果幀沒有子級,陣列將為空;如果文件位於跨域<iframe>中,children將返回null。 id只讀 實驗性-
一個字串,表示文件所包含的
<iframe>的id屬性值(例如<iframe id="foo" src="...">)。如果文件不在<iframe>中,或者<iframe>沒有設定id,則id將返回null。 name只讀 實驗性-
一個字串,表示文件所包含的
<iframe>的name屬性值(例如<iframe name="bar" src="...">)。如果文件不在<iframe>中,或者<iframe>沒有設定name,則name將返回null。 reasons只讀 實驗性-
一個
NotRestoredReasonDetails物件陣列,每個物件表示導航頁面被阻止使用 bfcache 的一個原因。如果文件位於跨域<iframe>中,reasons將返回null,但如果任何<iframe>阻止了頂級幀的 bfcache 使用,則父文件可能會顯示"masked"的reason。有關原因的更多詳細資訊,請參閱阻塞原因。 src只讀 實驗性-
一個字串,表示文件所包含的
<iframe>的源路徑(例如<iframe src="exampleframe.html">)。如果文件不在<iframe>中,則src將返回null。 url只讀 實驗性-
一個字串,表示導航頁面或
<iframe>的 URL。如果文件位於跨域<iframe>中,url將返回null。
報告同源 <iframe> 中的 bfcache 阻塞
當頁面嵌入同源 <iframe> 時,返回的 notRestoredReasons 值將包含一個物件陣列,位於 children 屬性中,表示與每個嵌入幀相關的阻塞原因。
例如
{
"children": [
{
"children": [],
"id": "iframe-id",
"name": "iframe-name",
"reasons": [],
"src": "./index.html",
"url": "https://www.example.com/iframe-examples.html"
},
{
"children": [],
"id": "iframe-id2",
"name": "iframe-name2",
"reasons": [{ "reason": "unload-listener" }],
"src": "./unload-examples.html",
"url": "https://www.example.com/unload-examples.html"
}
],
"id": null,
"name": null,
"reasons": [],
"src": null,
"url": "https://www.example.com"
}
報告跨域 <iframe> 中的 bfcache 阻塞
當頁面嵌入跨域幀時,為了避免洩露跨域資訊,共享的有關它們的資訊量受到限制。只包含外部頁面已知的資訊,以及跨域子樹是否導致 bfcache 阻塞。不包含阻塞原因或有關子樹較低級別的資訊(即使某些子級別是同源的)。
例如
{
"children": [
{
"children": [],
"id": "iframe-id",
"name": "iframe-name",
"reasons": [],
"src": "https://www.example2.com/",
"url": null
}
],
"id": null,
"name": null,
"reasons": [{ "reason": "masked" }],
"src": null,
"url": "https://www.example.com"
}
對於所有跨域 <iframe>,不報告任何阻塞原因;對於頂級幀,報告 "masked" 原因,以表示出於隱私目的隱藏了原因。請注意,"masked" 也可能用於隱藏使用者代理特定的原因;它並不總是表示 <iframe> 中存在問題。
阻塞原因
可能導致阻塞的原因有很多。儘管原因已標準化,但開發者應避免依賴於特定的原因措辭,並準備好處理新新增和刪除的原因。
規範中列出的值是:
"fetch"-
在解除安裝過程中,當前文件發起的一個 fetch(例如,透過
fetch())在進行中被取消。因此,頁面處於不穩定狀態,無法儲存在 bfcache 中。 "lock"-
在解除安裝過程中,持有的鎖和鎖請求被終止,因此頁面處於不穩定狀態,無法儲存在 bfcache 中。
"masked"-
確切原因出於隱私目的被隱藏。此值可能表示以下其中一項:
- 當前文件包含在跨域
<iframe>中的子級,它們阻止了在 bfcache 中的儲存。 - 由於使用者代理特定的原因,當前文件無法儲存在 bfcache 中。
- 當前文件包含在跨域
-
建立當前文件的原始導航出錯,阻止了將生成的錯誤文件儲存在 bfcache 中。
"parser-aborted"-
當前文件從未完成其初始 HTML 解析,阻止了將未完成的文件儲存在 bfcache 中。
"websocket"-
在解除安裝過程中,一個開啟的 WebSocket 連線被關閉,因此頁面處於不穩定狀態,無法儲存在 bfcache 中。
使用者代理特定的阻塞原因
還指定了一些瀏覽器可能使用的其他阻塞原因:
"audio-capture"-
文件透過使用 Media Capture and Streams 的
getUserMedia()並帶有音訊,請求了音訊捕獲許可權。 "background-work"-
文件透過呼叫
SyncManager的register()方法、PeriodicSyncManager的register()方法或BackgroundFetchManager的fetch()方法請求了後臺工作。 "broadcastchannel-message"-
當頁面儲存在前進/後退快取中時,頁面上的
BroadcastChannel連線接收到一條訊息以觸發message事件。 "idbversionchangeevent"-
在解除安裝過程中,文件有一個待處理的
IDBVersionChangeEvent。 "idledetector"-
在解除安裝過程中,文件有一個活動的
IdleDetector。 "keyboardlock""mediastream"-
在解除安裝時,一個 MediaStreamTrack 處於活動狀態。
"midi"-
文件透過呼叫
navigator.requestMIDIAccess()請求了 MIDI 許可權。 "modals"-
在解除安裝過程中顯示了使用者提示。
-
在解除安裝過程中,載入仍在進行中,因此文件未處於可以儲存在前進/後退快取中的狀態。
-
導航請求透過呼叫
window.stop()被取消,頁面未處於可以儲存在前進/後退快取中的狀態。 "non-trivial-browsing-context-group"-
此文件的瀏覽上下文組有多個頂級瀏覽上下文。
"otpcredential"-
文件建立了一個
OTPCredential。 "outstanding-network-request"-
在解除安裝過程中,文件有未完成的網路請求,並且未處於可以儲存在前進/後退快取中的狀態。
"paymentrequest"-
在解除安裝過程中,文件有一個活動的
PaymentRequest。 "pictureinpicturewindow"-
在解除安裝過程中,文件有一個活動的
PictureInPictureWindow。 "plugins"-
文件包含外掛。
"request-method-not-get"-
文件是透過 HTTP 請求建立的,該請求的方法不是
GET。 "response-auth-required"-
文件是透過需要 HTTP 認證的 HTTP 響應建立的。
"response-cache-control-no-store"-
文件是透過 HTTP 響應建立的,該響應的
Cache-Control頭部包含“no-store”令牌。 "response-cache-control-no-cache"-
文件是透過 HTTP 響應建立的,該響應的
Cache-Control頭部包含“no-cache”令牌。 "response-keep-alive"-
文件是透過包含
Keep-Alive頭部的 HTTP 響應建立的。 "response-scheme-not-http-or-https"-
文件是透過其 URL 方案不是 HTTP(S) 方案的響應建立的。
"response-status-not-ok"-
文件是透過其狀態不是 ok 狀態的 HTTP 響應建立的。
"rtc"-
在解除安裝過程中,一個
RTCPeerConnection或RTCDataChannel被關閉,因此頁面未處於可以儲存在前進/後退快取中的狀態。 "sensors"-
文件請求了感測器訪問許可權。
"serviceworker-added"-
當頁面位於前進/後退快取中時,文件的服務工作客戶端開始被 服務工作器 控制。
"serviceworker-claimed"-
當頁面位於前進/後退快取中時,文件的服務工作客戶端的活動 服務工作器 被宣告。
"serviceworker-postmessage"-
當頁面位於前進/後退快取中時,文件的服務工作客戶端的活動 服務工作器 收到了一條訊息。
"serviceworker-version-activated"-
當頁面位於前進/後退快取中時,文件的服務工作客戶端的活動 服務工作器 的版本被啟用。
"serviceworker-unregistered"-
當頁面位於前進/後退快取中時,文件的服務工作客戶端的活動 服務工作器 的服務工作器註冊被登出。
-
此文件位於
SharedWorkerGlobalScope的所有者集中。 "smartcardconnection"-
在解除安裝過程中,文件有一個活動的
SmartCardConnection。 "speechrecognition"-
在解除安裝過程中,文件有一個活動的
SpeechRecognition。 "storageaccess"-
文件透過使用 Storage Access API 請求了儲存訪問許可權。
"unload-listener"-
文件為
unload事件註冊了一個事件監聽器。 "video-capture"-
文件透過使用 Media Capture and Streams 的
getUserMedia()並帶有影片,請求了影片捕獲許可權。 "webhid"-
文件呼叫了 WebHID API 的
requestDevice()方法。 -
文件使用了 Web Share API 的
navigator.share()方法。 "webtransport"-
在解除安裝過程中,一個開啟的
WebTransport連線被關閉,因此頁面未處於可以儲存在前進/後退快取中的狀態。 "webxrdevice"-
文件建立了一個 XRSystem。
瀏覽器相容性
載入中…
另見
注意: 本文改編自 Chris Mills 和 Barry Pollard 的 前進/後退快取 notRestoredReasons API,最初於 2023 年在 developer.chrome.com 上釋出,採用 知識共享署名 4.0 許可。