最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - AbortSignal.timeout() in fetch request always responds with AbortError but not TimeoutError - Stack Overflow

programmeradmin0浏览0评论

I have following code:

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();

Here, getData uses fetch() to retrieve data from an API endpoint, I set signal property of request to AbortSignal.timeout(5_000) to implement timeout.

According to MDN documentation, AbortSignal.timeout(TIME_IN_MS) will return AbortSignal that will automatically abort after specified time. The signal aborts with either TimeoutError on timeout, or with AbortError due to pressing a browser stop button, closing the tab (or some other inbuilt "stop" operation).

The response that I get every time when running getData() is AbortError with message The user aborted a request. and never TimeoutError, even when I set browser to throttle to slow 3G and set time to 100ms. I also tried setting the response to take 10s in the server and in the front end to no throttle and timeout to 9000ms.

Why don't I get TimeoutError but only get AbortError?

Update 1:

This issue seems to only be for chromium-based browsers like Google Chrome, Microsoft Edge but works as Expected in Firefox.

Update 2:

As pointed by @Kaiido, this seems to be error of not only Chromium but also Safari. Issue is opened on both:

  • Chromium:
  • Safari: .cgi?id=246069

I have following code:

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();

Here, getData uses fetch() to retrieve data from an API endpoint, I set signal property of request to AbortSignal.timeout(5_000) to implement timeout.

According to MDN documentation, AbortSignal.timeout(TIME_IN_MS) will return AbortSignal that will automatically abort after specified time. The signal aborts with either TimeoutError on timeout, or with AbortError due to pressing a browser stop button, closing the tab (or some other inbuilt "stop" operation).

The response that I get every time when running getData() is AbortError with message The user aborted a request. and never TimeoutError, even when I set browser to throttle to slow 3G and set time to 100ms. I also tried setting the response to take 10s in the server and in the front end to no throttle and timeout to 9000ms.

Why don't I get TimeoutError but only get AbortError?

Update 1:

This issue seems to only be for chromium-based browsers like Google Chrome, Microsoft Edge but works as Expected in Firefox.

Update 2:

As pointed by @Kaiido, this seems to be error of not only Chromium but also Safari. Issue is opened on both:

  • Chromium: https://bugs.chromium/p/chromium/issues/detail?id=1431720
  • Safari: https://bugs.webkit/show_bug.cgi?id=246069
Share edited Apr 10, 2023 at 12:18 Aayush Karna asked Apr 9, 2023 at 9:18 Aayush KarnaAayush Karna 1182 silver badges9 bronze badges 2
  • Is 5_000 a typo? – James Commented Apr 9, 2023 at 15:17
  • 2 @James no it's not a typo, it's numeric separator which was introduced to the language in ES2021 to improve readability of numeric literal, check out MDN docs. – Aayush Karna Commented Apr 9, 2023 at 15:25
Add a ment  | 

1 Answer 1

Reset to default 8

This is indeed a Chrome and Safari bug.

I just opened CRBUG 1431754, and Safari had BUG 246069 for quite some time now.

According to the specs

To abort a fetch() call with a promise, request, responseObject, and an error:

  1. Reject promise with error.

In this case you hit the abort steps set at the step 11 of the fetch() method algorithm:

4.11 Abort the fetch() call with p, request, responseObject, and requestObject’s signal’s abort reason.

Here "requestObject’s signal’s abort reason" is the object stored in our AbortSignal.reason, so not only should we have the same kind of DOMException, but it should even be the same object.

Here is another test (hitting the step 4. this time, but the result is the same) that does repro the issue:

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

Unfortunately I don't see what you can do about it... checking the original AbortSignal#reason at the time the fetch() promise rejects might do it, but that sounds a bit hackish and prone to false positives.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论
ok 不同模板 switch ($forum['model']) { /*case '0': include _include(APP_PATH . 'view/htm/read.htm'); break;*/ default: include _include(theme_load('read', $fid)); break; } } break; case '10': // 主题外链 / thread external link http_location(htmlspecialchars_decode(trim($thread['description']))); break; case '11': // 单页 / single page $attachlist = array(); $imagelist = array(); $thread['filelist'] = array(); $threadlist = NULL; $thread['files'] > 0 and list($attachlist, $imagelist, $thread['filelist']) = well_attach_find_by_tid($tid); $data = data_read_cache($tid); empty($data) and message(-1, lang('data_malformation')); $tidlist = $forum['threads'] ? page_find_by_fid($fid, $page, $pagesize) : NULL; if ($tidlist) { $tidarr = arrlist_values($tidlist, 'tid'); $threadlist = well_thread_find($tidarr, $pagesize); // 按之前tidlist排序 $threadlist = array2_sort_key($threadlist, $tidlist, 'tid'); } $allowpost = forum_access_user($fid, $gid, 'allowpost'); $allowupdate = forum_access_mod($fid, $gid, 'allowupdate'); $allowdelete = forum_access_mod($fid, $gid, 'allowdelete'); $access = array('allowpost' => $allowpost, 'allowupdate' => $allowupdate, 'allowdelete' => $allowdelete); $header['title'] = $thread['subject']; $header['mobile_link'] = $thread['url']; $header['keywords'] = $thread['keyword'] ? $thread['keyword'] : $thread['subject']; $header['description'] = $thread['description'] ? $thread['description'] : $thread['brief']; $_SESSION['fid'] = $fid; if ($ajax) { empty($conf['api_on']) and message(0, lang('closed')); $apilist['header'] = $header; $apilist['extra'] = $extra; $apilist['access'] = $access; $apilist['thread'] = well_thread_safe_info($thread); $apilist['thread_data'] = $data; $apilist['forum'] = $forum; $apilist['imagelist'] = $imagelist; $apilist['filelist'] = $thread['filelist']; $apilist['threadlist'] = $threadlist; message(0, $apilist); } else { include _include(theme_load('single_page', $fid)); } break; default: message(-1, lang('data_malformation')); break; } ?>