如何使用超时机制运行异步功能



afterrunTaskWithTimeout(), 如何在"发生任务超时错误"后成功打印"任务最终"?

谢谢。

async function runTaskWithTimeout() {
try {
const timeout = setTimeout(() => {
console.log('task timeout error happen')
throw new Error('timeout error happened')
}, 2000)
console.log('task start')
await wait(3000);
/** assume this is async function*/
clearTimeout(timeout);
console.log('task complete')
} catch (error) {
console.log('catch error', error.message);
} finally {
console.log('task finally')
}
}
async function wait(ms) {
return new Promise(resolve => {
setTimeout(() => { resolve(ms);}, ms);
});
}

您可以轻松地使用Promise.race进行超时。这里有一个函数(就像你的wait函数一样)在延迟后结算一个承诺,但与wait不同的是,它拒绝承诺,并出现包含给定消息的错误:

const timeout = (ms, message) => {
return new Promise((_, reject) => {
setTimeout(() => {
reject(new Error(message));
}, ms);
});
};

然后在runTaskWithTimeout中,您将超时与实际工作进行比赛:

async function runTaskWithTimeout() {
console.log("Running");
try {
await Promise.race([
timeout(3000), // 3000 = the maximum time to wait
(async () => {
// ...do the real work, modelled here as `wait`...
await wait(2000);
})()
]);
console.log("task complete")
} catch (error) {
console.log("catch error", error.message);
} finally {
console.log("task finally")
}
}

Promise.race用你传递它的第一个承诺的结果来解决它的承诺。因此,如果实际工作在超时之前完成(或失败),那就是Promise.race承诺的结果。如果超时发生在实际工作完成之前,则超时是Promise.race的结果。

实时示例使用timeoutwait的随机值,因此有时超时发生在工作完成之前,而其他时候则不会:

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
const timeout = (ms, message) => {
return new Promise((_, reject) => {
setTimeout(() => {
reject(new Error(message));
}, ms);
});
};
async function runTaskWithTimeout() {
console.log("Running");
try {
// Just for the purposes of example, let's make it random which
// comes first:
const timeoutLength = Math.floor(Math.random() * 1000);
const waitLength    = Math.floor(Math.random() * 1000);
await Promise.race([
timeout(timeoutLength),
(async () => {
// This is the real work
await wait(waitLength);
})()
]);
console.log("task complete")
} catch (error) {
console.log("catch error", error.message);
} finally {
console.log("task finally")
}
}
document.getElementById("run").addEventListener("click", () => {
runTaskWithTimeout();
});
<input type="button" id="run" value="Run">

注意:以上只是一个草图。在完整的实现中,您需要一种方法让"实际工作"知道超时已经发生,以便它可以停止它正在执行的任何操作。您可能希望为此使用AbortControllerAbortSignal(如果您不执行 Web 代码,则在您的环境中使用等效项)。您可能希望runTaskWitHTimeout返回"实际工作"的实现值(在上面,它可以通过从非错误分支中的await Promise.race返回值来做到这一点)。

最新更新