监控 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 对象记录到控制台。这些对象具有以下结构,它表示顶级框架的阻止状态。

js
{
  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,则父文档可能会显示 reason"masked"。有关原因的更多详细信息,请参见 阻止原因

src 只读 实验性

一个字符串,表示包含文档的 <iframe> 的源路径(例如 <iframe src="exampleframe.html">)。如果文档不在 <iframe> 中,则 src 将返回 null

url 只读 实验性

一个字符串,表示导航页面或 <iframe> 的 URL。如果文档位于跨域 <iframe> 中,则 url 将返回 null

报告同源 <iframe> 中的 bfcache 阻止

当页面嵌入同源 <iframe> 时,返回的 notRestoredReasons 值将包含一个对象数组,该数组位于 children 属性中,表示与每个嵌入框架相关的阻止原因。

例如:

js
{
  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 阻止。不包含任何阻止原因或关于子树较低级别(即使某些子级别是同源)的信息。

例如:

js
{
  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())在进行中被取消。因此,页面没有处于可以存储在 bfcache 中的稳定状态。

"lock"

在卸载时,持有的锁和锁请求被终止,因此页面没有处于可以存储在 bfcache 中的稳定状态。

"masked"

出于隐私目的,确切原因被隐藏。此值可以表示以下几种情况之一:

  • 当前文档包含跨域 <iframe> 中的子级,它们阻止了存储在 bfcache 中。
  • 当前文档无法因特定于用户代理的原因而存储在 bfcache 中。

创建当前文档的原始导航发生错误,并且阻止了将生成的错误文档存储在 bfcache 中。

"parser-aborted"

当前文档从未完成其初始 HTML 解析,并且阻止了将未完成的文档存储在 bfcache 中。

"websocket"

在卸载时,打开的 WebSocket 连接被关闭,因此页面没有处于可以存储在 bfcache 中的稳定状态。

一些浏览器可能会使用其他阻止原因,例如:

"unload-listener"

页面注册了一个 unload 处理程序,这会阻止使用 bfcache。这起到一个有用的警告作用,因为 unload 已被弃用。有关更多信息,请参见 使用说明

"response-cache-control-no-store"

该页面使用no-store作为Cache-Control头部的值。

该页面从另一个仍然包含对该页面引用的页面打开,例如使用“重复标签”功能。

浏览器兼容性

BCD 表格仅在浏览器中加载

另请参见

注意: 本文改编自 Back/forward cache notRestoredReasons API by Chris Mills and Barry Pollard,最初发布于 developer.chrome.com,发布于 2023 年,根据 知识共享署名 4.0 许可证