Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

备稿计划: 使用 AbortSignal 而非 Promise.race() 做 fetch 超时 #119

Open
iugo opened this issue Jul 19, 2022 · 0 comments
Open

Comments

@iugo
Copy link
Member

iugo commented Jul 19, 2022

总结: fetch 增加超时只需要使用 AbortSignal.timeout() 即可.
例如 5000ms 超时为 fetch('https://url', { signal: AbortSignal.timeout(5000) }) 即可.

之前遇到想要中断操作时, 都是使用 Promise.race().

但是对于 fetch, 可以通过 AbortSignal 来避免 Promise 进一步执行.

对于浏览器环境和 Deno 环境, 都可以使用. 但返回的错误是有区别的. 使用如下代码进行测试:

浏览器测试代码:

async function test() {
  const c = new AbortController();
  setTimeout(() => {
    c.abort(new Error('haha'));
  }, 20);
  await fetch('https://www.baidu.com', { signal: c.signal }).then(res => {
    console.log(res.status);
  });
}

test().catch((err) => {
  console.log(err instanceof Error);
  console.log(typeof err);
  console.log(err.toString());
});

Deno 测试代码:

Deno.test('test', async () => {
  async function test() {
    const c = new AbortController();
    setTimeout(() => {
      c.abort(new Error('haha'));
    }, 20);
    await fetch('https://www.baidu.com', { signal: c.signal }).then((res) => {
      console.log(res.status);
    });
  }

  await test().catch((err) => {
    console.log(err instanceof Error);
    console.log(typeof err);
    console.log(err.toString());
  });
});

浏览器返回的错误为: AbortError: The user aborted a request. 无论 .abort() 方法传入什么参数.

而 Deno 下则会返回传入的参数, 可以替代返回的错误.

查看 MDN 文档:

Screen_Shot_2022-07-19_at_15.26.17

从文档可知, abort 传参是新特性, Chrome 还没有添加相关支持. 甚至 AbortError 特性也是最新才加上了.

前端使用 AbortError 还是要谨慎, 可能老款浏览就不支持. Deno 则可以放心使用.

还有另一种做法, 可能兼容性更好, 尤其是在 Chrome 还没在支持 .abort() 参数时.

.timeout() https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/timeout

Screen_Shot_2022-07-19_at_16.34.58

在上个月 Chrome 刚刚支持. 这个得到了大家广泛的响应.

Deno.test('test', async () => {
  async function test() {
    await fetch('https://www.baidu.com', { signal: AbortSignal.timeout(5000) })
      .then((res) => {
        console.log(res.status);
      });
  }

  await test().catch((err) => {
    console.log(err instanceof Error);
    console.log(typeof err);
    console.log(err.toString());
  });
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant