promise ajax 超时 中断

用到 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 属性置为 truefetch() 外部解决会利用这些信息停止掉申请。

如果应用 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);
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *