監控 bfcache 阻止原因

可用性有限

此特性不是基線特性,因為它在一些最廣泛使用的瀏覽器中不起作用。

實驗性: 這是一項實驗性技術
在生產中使用此技術之前,請仔細檢查瀏覽器相容性表格

PerformanceNavigationTiming.notRestoredReasons 屬性報告了當前文件在導航時被阻止使用 bfcache 的資訊。開發者可以使用這些資訊來識別需要更新才能與 bfcache 相容的頁面,從而提高網站效能。

前進/後退快取(bfcache)

現代瀏覽器為歷史導航提供了一種最佳化功能,稱為前進/後退快取(bfcache)。這使使用者在返回已訪問過的頁面時能獲得即時載入體驗。頁面可能因各種原因被阻止進入 bfcache,或在 bfcache 中被驅逐,其中一些是規範要求的,另一些是瀏覽器實現特有的。

為了能夠監控 bfcache 阻塞原因,PerformanceNavigationTiming 類包含一個 notRestoredReasons 屬性。該屬性返回一個 NotRestoredReasons 物件,其中包含有關頂級幀和文件中所有 <iframe> 的相關資訊。

  • bfcache 使用被阻止的原因。
  • 詳細資訊,例如幀的 idname,以幫助識別 HTML 中的 <iframe>

注意: 歷史上,已廢棄的 PerformanceNavigation.type 屬性用於監控 bfcache,開發者透過測試 type"TYPE_BACK_FORWARD" 來獲取 bfcache 命中率的指示。然而,這並未提供任何 bfcache 阻塞的原因或其他資料。今後應使用 notRestoredReasons 屬性來監控 bfcache 阻塞。

記錄 bfcache 阻塞原因

可以使用 PerformanceObserver 獲取持續的 bfcache 阻塞資料,如下所示:

js
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 阻塞資料。

js
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 物件記錄到控制檯。這些物件具有以下結構,代表了頂級幀的阻塞狀態:

json
{
  "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 屬性中,表示與每個嵌入幀相關的阻塞原因。

例如

json
{
  "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 阻塞。不包含阻塞原因或有關子樹較低級別的資訊(即使某些子級別是同源的)。

例如

json
{
  "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"

文件透過呼叫 SyncManagerregister() 方法、PeriodicSyncManagerregister() 方法或 BackgroundFetchManagerfetch() 方法請求了後臺工作。

"broadcastchannel-message"

當頁面儲存在前進/後退快取中時,頁面上的 BroadcastChannel 連線接收到一條訊息以觸發 message 事件。

"idbversionchangeevent"

在解除安裝過程中,文件有一個待處理的 IDBVersionChangeEvent

"idledetector"

在解除安裝過程中,文件有一個活動的 IdleDetector

"keyboardlock"

在解除安裝過程中,由於呼叫了 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"

在解除安裝過程中,一個 RTCPeerConnectionRTCDataChannel 被關閉,因此頁面未處於可以儲存在前進/後退快取中的狀態。

"sensors"

文件請求了感測器訪問許可權。

"serviceworker-added"

當頁面位於前進/後退快取中時,文件的服務工作客戶端開始被 服務工作器 控制。

"serviceworker-claimed"

當頁面位於前進/後退快取中時,文件的服務工作客戶端的活動 服務工作器 被宣告。

"serviceworker-postmessage"

當頁面位於前進/後退快取中時,文件的服務工作客戶端的活動 服務工作器 收到了一條訊息。

"serviceworker-version-activated"

當頁面位於前進/後退快取中時,文件的服務工作客戶端的活動 服務工作器 的版本被啟用。

"serviceworker-unregistered"

當頁面位於前進/後退快取中時,文件的服務工作客戶端的活動 服務工作器 的服務工作器註冊被登出。

"sharedworker"

此文件位於 SharedWorkerGlobalScope 的所有者集中。

"smartcardconnection"

在解除安裝過程中,文件有一個活動的 SmartCardConnection

"speechrecognition"

在解除安裝過程中,文件有一個活動的 SpeechRecognition

"storageaccess"

文件透過使用 Storage Access API 請求了儲存訪問許可權。

"unload-listener"

文件為 unload 事件註冊了一個事件監聽器。

"video-capture"

文件透過使用 Media Capture and Streams 的 getUserMedia() 並帶有影片,請求了影片捕獲許可權。

"webhid"

文件呼叫了 WebHID APIrequestDevice() 方法。

"webshare"

文件使用了 Web Share APInavigator.share() 方法。

"webtransport"

在解除安裝過程中,一個開啟的 WebTransport 連線被關閉,因此頁面未處於可以儲存在前進/後退快取中的狀態。

"webxrdevice"

文件建立了一個 XRSystem

瀏覽器相容性

另見

注意: 本文改編自 Chris Mills 和 Barry Pollard 的 前進/後退快取 notRestoredReasons API,最初於 2023 年在 developer.chrome.com 上釋出,採用 知識共享署名 4.0 許可