关于 fetch,几个常被问到的问题
【摘要】 整理 fetch 使用中的四个常见问题——用 AbortSignal.timeout 设超时、AbortController 取消请求、keepalive 保证页面关闭时的上报、以及重试要区分 5xx 与 4xx 并做指数退避。
用 fetch 发请求很简单,但真到业务里,超时、取消、重试这些一个都躲不掉。整理几个经常被问到的点。
怎么给 fetch 设超时?
早年的写法是 setTimeout 配 AbortController,到点手动 abort。现在简单些:
const res = await fetch(url, { signal: AbortSignal.timeout(5000) });
AbortSignal.timeout 生成一个五秒后自动中止的信号,超时会抛 TimeoutError。想自己控制时机就用 AbortController,两者不冲突。
怎么取消一个已经发出的请求?
const ctrl = new AbortController();
fetch(url, { signal: ctrl.signal });
ctrl.abort();
调用 abort() 之后请求会被中断,fetch 的 Promise 以 AbortError 拒绝。页面切换、组件卸载时记得调,不然请求还在飞,回来可能把旧数据盖到新页面上。
keepalive 是干嘛的?
navigator.sendBeacon(url, data);
fetch(url, { method: 'POST', body: data, keepalive: true });
页面即将关闭时,普通的 fetch 会被浏览器掐掉,埋点上不去。keepalive: true 告诉浏览器让这个请求活过页面卸载。它有体积上限(一般 64KB),超了会失败,所以只适合小数据上报。
失败要自动重试吗?
要看是什么错。网络抖动、503 这类可以重试;400、401、422 这类是请求本身有问题,重试一百次也一样。
async function fetchWithRetry(url, opts = {}, times = 2) {
for (let i = 0; i <= times; i++) {
try {
const res = await fetch(url, opts);
if (res.status < 500) return res;
if (i === times) return res;
} catch (e) {
if (i === times) throw e;
}
await new Promise((r) => setTimeout(r, 300 * 2 ** i));
}
}
重试间隔按指数退避,尽量别一下子连续打,服务器本来就忙的时候更容易被打垮。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)