fetchLater API 源试用

网页通常需要将数据(或“信标”)发回其服务器,例如,用户当前会话的分析数据。对于开发者来说,这需要权衡:减少可能多余的持续请求,同时又要避免在信标发送之前标签页关闭或用户离开时错失数据。

传统上,开发者使用 pagehidevisibilitychange 事件捕获页面在卸载时的数据,然后使用 navigator.sendBeacon()fetch()keepalive 一起发送信标数据。不过,这两种事件都存在一些棘手的极端情况,这些情况因用户的浏览器而异,有时这些事件根本不会到达,尤其是在移动设备上。

fetchLater() 旨在通过单个 API 调用来替换这种复杂性。它的用途与其名称完全相符:它会要求浏览器确保在未来某个时间点发出请求,即使网页关闭或用户离开也是如此。

fetchLater() 已在 Chrome 121 版(2024 年 1 月发布)中推出,可供用户在源试用后参与测试,该试用将持续到 2024 年 9 月 3 日。

fetchLater() API

const fetchLaterResult = fetchLater(request, options);

fetchLater() 接受两个参数,通常与 fetch() 的参数相同:

  • request,可以是字符串网址,也可以是 Request 实例。
  • 可选的 options 对象,用于使用名为 activateAfter 的超时来扩展 fetch() 中的 options

fetchLater() 会返回一个 FetchLaterResult,目前仅包含一个只读属性 activated,该属性将在“稍后”时间过后且已提取数据后设为 true。系统会舍弃对 fetchLater() 请求的任何响应。

request

最简单的用法是使用单独的网址:

fetchLater('/endpoint/');

不过,与 fetch() 一样,您也可以在 fetchLater() 请求中设置大量选项,包括自定义标头、凭据行为、POST 正文以及可能用于取消请求的 AbortController signal

fetchLater('/endpoint/', {
  method: 'GET',
  cache: 'no-store',
  mode: 'same-origin',
  headers: {Authorization: 'SUPER_SECRET'},
});

options

options 对象使用超时 activateAfter 扩展了 fetch() 的选项,以便您在超时后或页面卸载时(以先到者为准)触发请求。

这样,您就可以在尽可能晚获取数据与更及时获取数据之间进行权衡。

例如,如果您的应用通常会被用户在整个工作日内保持打开状态,您可能希望设置一小时的超时时间,以确保获得更精细的分析数据,同时在用户在该一小时内退出应用时仍能发送信标。然后,您可以为接下来一小时的分析设置新的 fetchLater()

const hourInMilliseconds = 60 * 60 * 1000;
fetchLater('/endpoint/', {activateAfter: hourInMilliseconds});

用法示例

在现场衡量核心 Web 指标时,会遇到一个问题,即在用户实际离开网页之前,任何性能指标都可能会发生变化。例如,更大的布局偏移随时都可能发生,或者页面可能需要更长时间才能响应互动。

不过,您不希望因网页卸载时出现错误或未完成信标传送而冒丢失所有效果数据的风险。它是 fetchLater() 的理想候选人。

在此示例中,web-vitals.js 库用于监控指标,fetchLater() 用于将结果报告到分析端点:

import {onCLS, onINP, onLCP} from 'web-vitals';

const queue = new Set();
let fetchLaterController;
let fetchLaterResult;

function updateQueue(metricUpdate) {
  // If there was an already complete request for whatever
  // reason, clear out the queue of already-sent updates.
  if (fetchLaterResult?.activated) {
    queue.clear();
  }

  queue.add(metricUpdate);

  // JSON.stringify used here for simplicity and will likely include
  // more data than you need. Replace with a preferred serialization.
  const body = JSON.stringify([...queue]);

  // Abort any existing `fetchLater()` and schedule a new one with
  // the update included.
  fetchLaterController?.abort();
  fetchLaterController = new AbortController();
  fetchLaterResult = fetchLater('/analytics', {
    method: 'POST',
    body,
    signal: fetchLaterController.signal,
    activateAfter: 60 * 60 * 1000, // Timeout to ensure timeliness.
  });
}

onCLS(updateQueue);
onINP(updateQueue);
onLCP(updateQueue);

每次收到指标更新时,系统都会使用 AbortController 取消所有现有的定期 fetchLater(),并创建包含更新的新 fetchLater()

试用 fetchLater()

如前所述,在 Chrome 126 之前,fetchLater() 仅在源试用中提供。如需了解与来源试用相关的背景信息,请参阅开始使用来源试用

对于本地测试,您可以使用 chrome://flags/#enable-experimental-web-platform-features 中的“Experimental Web Platform features”标志启用 fetchLater。您还可以通过在命令行中使用 --enable-experimental-web-platform-features 或更具针对性的 --enable-features=FetchLaterAPI 标志运行 Chrome 来启用此功能。

如果您要在公开网页上使用它,请务必先进行功能检测,方法是检查是否已定义全局 fetchLater,然后再使用它:

if (globalThis.fetchLater) {
  // Set up beaconing using fetchLater().
  // ...
}

反馈

开发者反馈对完善新的 Web API 至关重要,因此请在 GitHub 上提交问题和反馈

更多信息