Window: fetchLater() 方法

可用性有限

此特性不是基线特性,因为它在一些最广泛使用的浏览器中不起作用。

实验性: 这是一项实验性技术
在生产中使用此技术之前,请仔细检查浏览器兼容性表格

Window 接口的 fetchLater() 方法创建了一个延迟抓取。

fetchLater() 请求会在页面导航离开(页面被销毁或进入 bfcache),或者在提供的 activateAfter 超时后发送——以先发生者为准。

fetchLater() 方法返回一个 FetchLaterResult 对象,其中包含一个 activated 值,表示请求是否已发送。请注意,该方法不返回实际抓取的结果(因为它通常在文档被销毁后发送),并且抓取的整个响应,包括正文和标头,都会被忽略。

请求主体为 ReadableStream 的请求无法被延迟。

fetchLater() 方法由 connect-src 内容安全策略指令控制,而不是由检索到的资源的指令控制。

语法

js
fetchLater(resource)
fetchLater(resource, options)

参数

fetchLater() 方法接受与 fetch() 相同的所有参数,但增加了一个 activateAfter 选项。

resource

这定义了您希望抓取的资源。与 fetch() 相同,这可以是

  • 一个字符串或任何其他具有 stringifier 的对象——包括一个 URL 对象——它提供您要抓取的资源的 URL。URL 可以相对于基本 URL,在窗口上下文中,基本 URL 是文档的 baseURI
  • 一个 Request 对象。
options 可选

一个 DeferredRequestInit 对象,其中包含您要应用于请求的任何自定义设置,包括一个 activateAfter 超时值,它定义了结果在发送前应延迟多长时间。

异常

fetch() 的相同异常可能会针对 fetchLater() 抛出,以及以下附加异常

QuotaExceededError

由于超出可用配额,此功能的使用被阻止。有关更多详细信息,请参阅 fetchLater() 配额fetchLater() 的调用者几乎在所有情况下都应保持防御性并捕获 QuotaExceededError 错误,尤其是当他们嵌入第三方 JavaScript 时。

RangeError DOMException

当指定负 activateAfter 值时抛出。

TypeError DOMException

除了 fetch() 的原因外,此异常还会针对 ReadableStream 请求(无法延迟)或使用不可信 URL(例如 http://)时抛出。

返回值

一个 FetchLaterResult,其中包含一个 activated 布尔属性,指示请求是否已发送。

注意:一旦抓取请求发送,其响应——包括主体和标头——将不可用并被忽略。

示例

fetchLater() 配额文章提供了配额如何应用的示例。

GET 请求延迟到页面导航离开或关闭

js
fetchLater("/send_beacon");

POST 请求延迟约一分钟

在此示例中,我们创建一个 Request,并提供一个 activateAfter 值以将请求发送延迟 60,000 毫秒(或一分钟)

js
fetchLater("/send_beacon", {
  method: "POST",
  body: getBeaconData(),
  activateAfter: 60000, // 1 minute
});

注意:实际发送时间未知,因为浏览器可能会等待更长或更短的时间,例如为了优化延迟抓取的批处理。

通过 try/catch 将 POST 请求延迟约一分钟

与上述示例相同,但最佳实践是将其封装在 try/catch 中

js
try {
  fetchLater("/send_beacon", {
    method: "POST",
    body: getBeaconData(),
    activateAfter: 60000, // 1 minute
  });
} catch (e) {
  if (e instanceof QuotaExceededError) {
    // Handle the quota error
  } else {
    // Handle other errors
  }
}

POST 请求延迟约一分钟并创建一个函数来检查是否已发送

js
const result = fetchLater("https://report.example.com", {
  method: "POST",
  body: JSON.stringify(myReport),
  activateAfter: 60000 /* 1 minute */,
});

function checkIfFetched() {
  return result.activated;
}

更新待处理请求

在此示例中,我们使用 AbortController 取消并重新创建请求

js
let beaconResult = null;
let beaconAbort = null;

function updateBeacon(data) {
  const pending = !beaconResult || !beaconResult.activated;
  if (pending && beaconAbort) {
    beaconAbort.abort();
  }

  createBeacon(data);
}

function createBeacon(data) {
  if (beaconResult && !beaconResult.activated) {
    // Avoid creating duplicated beacon if the previous one is still pending.
    return;
  }

  beaconAbort = new AbortController();
  beaconResult = fetchLater({
    url: data,
    signal: beaconAbort.signal,
  });
}

无效示例

以下任何对 fetchLater() 的调用都将抛出

js
// Only potentially trustworthy URLs are supported
fetchLater("http://untrusted.example.com");

// The length of the deferred request has to be known
fetchLater("https://origin.example.com", { body: someDynamicStream });

// Deferred fetching only works on active windows
const detachedWindow = iframe.contentWindow;
iframe.remove();
detachedWindow.fetchLater("https://origin.example.com");

规范

规范
Fetch
# deferred-fetch

浏览器兼容性

另见