获取请求中的 AbortSignal.timeout() 始终响应 AbortError 但不响应 TimeoutError

Aay*_*rna 5 javascript fetch

我有以下代码:

const getData = async function () {
  try {
    const response = await fetch(`${API_URL}/cars`, {
      signal: AbortSignal.timeout(5_000),
    });

    console.log(response);
  } catch (err) {
    console.log(err.name); //AbortError
    console.dir(err);
  }
};

getData();
Run Code Online (Sandbox Code Playgroud)

在这里,getData 用于fetch()从 API 端点检索数据,我将signalrequest 的属性设置为AbortSignal.timeout(5_000)以实现超时。

根据 MDN 文档,AbortSignal.timeout(TIME_IN_MS)将返回AbortSignal将在指定时间后自动中止。该信号会因TimeoutError超时或由于AbortError按下浏览器停止按钮、关闭选项卡(或某些其他内置“停止”操作)而中止。

我每次运行时得到的响应getData()都是AbortError消息The user aborted a request.,但从来没有TimeoutError,即使我将浏览器设置为减慢 3G 并将时间设置为 100 毫秒。我还尝试将服务器中的响应设置为 10 秒,前端设置为无限制,超时设置为 9000 毫秒。

为什么我没有得到TimeoutError而只是得到AbortError

更新1:

此问题似乎仅适用于基于 chromium 的浏览器,例如 Google Chrome、Microsoft Edge,但在 Firefox 中却按预期工作。

更新2:

正如 @Kaiido 所指出的,这似乎不仅是 Chromium 的错误,也是 Safari 的错误。问题已在以下两个方面展开:

Kai*_*ido 6

这确实是 Chrome 和 Safari 的 bug。

\n

我刚刚打开CRBUG 1431754,Safari 已经有BUG 246069相当长一段时间了。

\n

根据规格

\n
\n

要中止fetch()带有promiserequestresponseObjecterror的调用:

\n
    \n
  1. 拒绝有错误的承诺
  2. \n
\n
\n

在这种情况下,您将执行方法算法第 11 步中设置的中止步骤fetch()

\n
\n

4.11fetch()使用prequestresponseObjectrequestObject \xe2\x80\x99s 信号\xe2\x80\x99s 中止原因中止调用。

\n
\n

这里“ requestObject \xe2\x80\x99s signal\xe2\x80\x99s abort Reason”是存储在 our 中的对象AbortSignal.reason,所以我们不仅应该有相同类型的DOMException,而且它甚至应该是相同的对象。

\n

这是另一个重现该问题的测试(这次是执行步骤 4,但结果是相同的):

\n

\r\n
\r\n
(async () => {\n  const signal = AbortSignal.timeout(0);\n  // Wait for the signal times out\n  await new Promise((res) => setTimeout(res));\n  const { reason } = signal;\n  try {\n   await fetch("./",{ signal });\n  }\n  catch(fetchErr) {\n    console.log({\n        reason: reason.name,      // Expected: "TimeoutError"\n      fetchErr: fetchErr.name,  // Expected: "TimeoutError"\n      same: fetchErr === reason // Expected: true\n    });\n  }\n})();
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

不幸的是,我不知道你能对此做些什么......AbortSignal#reasonfetch()承诺拒绝时检查原始文件可能会做到这一点,但这听起来有点黑客并且容易出现误报。

\n