用到 promise.race
function waitWithTimeout(promise, timeout, timeoutMessage = "timeout") {
let timer;
const timeoutPromise = new Promise((_, reject) => {
timer = setTimeout(() => reject(timeoutMessage), timeout);
});
return Promise.race([timeoutPromise, promise])
.finally(() => clearTimeout(timer)); // 别忘了清 timer
}
(async () => {
const business = new Promise(resolve => setTimeout(resolve, 1000 * 10));
try {
await waitWithTimeout(business, 1000);
console.log("[Success]");
} catch (err) {
console.log("[Error]", err); // [Error] timeout
}
})();
// 上述,返回一个对象,对象里有 resolve, reject,promise
// 如果想干掉这个请求, obj.reject();
axios 超时
侥幸的是 Axios 的确能够解决超时,只须要在 options
里增加一个 timeout: 3000
就能解决问题。如果超时,能够在 catch
块中检测并解决:
try {...}
catch (err) {
if (err.isAxiosError && !err.response && err.request
&& err.message.startsWith("timeout")) {
// 如果是 Axios 的 request 谬误,并且音讯是延时音讯
// TODO 解决超时
}
}
finally {...}
解决 fetch() 超时
fetch()
本人不具备解决超时的能力,须要咱们判断超时后通过 AbortController
来触发“勾销”申请操作。如果须要中断一个 fetch()
操作,只需从一个 AbortController
对象获取 signal
,并将这个信号对象作为 fetch()
的选项传入。大略就是这样:
const ac = new AbortController();
const { signal } = ac;
fetch(url, { signal }).then(res => {
// TODO 解决业务
});
// 1 秒后勾销 fetch 操作
setTimeout(() => ac.abort(), 1000);
ac.abort()
会向 signal
发送信号,触发它的 abort
事件,并将其 .aborted
属性置为 true
。fetch()
外部解决会利用这些信息停止掉申请。
如果应用 await
的模式来解决,须要把 setTimeout(...)
放在 fetch(...)
之前:
完整封装
async function fetchWithTimeout(timeout, resoure, init = {}) {
const ac = new AbortController();
const signal = ac.signal;
const timer = setTimeout(() => {
console.log("It's timeout");
return ac.abort();
}, timeout);
try {
return await fetch(resoure, { ...init, signal });
} finally {
clearTimeout(timer);
}
}