使用 promise.race 结合 settimeout 可以实现异步操作的超时过滤。具体做法是创建一个在指定毫秒后自动拒绝的 promise,并将其与原 promise 放入 promise.race 中竞争;原 promise 先完成则返回结果,定时器先触发则抛出超时异常。

Promise.race 如何拦截正常返回值
Promise.race 会返回一个 Promise,该 Promise 的状态取决于传入数组中第一个改变状态的 Promise。如果原任务成功,它直接透传结果;如果定时器先触发,它会透传拒绝原因(即超时错误)。

function withTimeout(promise, ms) {
const timer = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Timeout')), ms);
});
return Promise.race([promise, timer]);
}
// 模拟耗时操作
const task = new Promise(resolve => {
setTimeout(() => resolve('Success'), 1000);
});
withTimeout(task, 500)
.then(console.log)
.catch(err => console.error(err.message));
// Output: Timeout
上述代码中,task 需要 1000ms 完成,而超时限制为 500ms。因此 timer 先变为 rejected 状态,Promise.race 捕获到拒绝并向下传递,最终输出 'Timeout'。
如何处理超时后的资源清理
当超时发生时,虽然主逻辑被中断,但底层可能仍有未完成的 I/O 或定时器。最佳实践是在超时拒绝时主动取消或清理相关资源,防止内存泄漏或无效计算继续消耗 CPU。

function withCleanupTimeout(promise, ms, onCancel) {
let cancelled = false;
const timer = new Promise((_, reject) => {
setTimeout(() => {
cancelled = true;
if (onCancel) onCancel();
reject(new Error('Timeout'));
}, ms);
});
return Promise.race([promise, timer])
.catch(err => {
if (cancelled) throw err;
throw err;
});
}
// 使用示例
withCleanupTimeout(fetchData(), 2000, () => {
console.log('Cleaning up resources...');
})
.catch(e => console.log(e.message));
在这个增强版中,onCancel 回调允许在超时时执行清理逻辑。通过标记 cancelled 状态,可以区分是正常失败还是超时导致的失败,从而进行不同的错误处理。
基于输入参数 ms 的动态超时行为
当传入的 ms 参数大于实际任务耗时且小于其他任务的耗时时,Promise.race 将优先返回原任务的成功值。例如,若任务耗时 100ms,设置超时为 5000ms,则不会触发超时错误,而是正常返回结果。
const fastTask = new Promise(resolve => {
setTimeout(() => resolve('Fast Result'), 100);
});
withTimeout(fastTask, 5000)
.then(res => console.log(res))
.catch(err => console.error(err.message));
// Output: Fast Result
此例验证了当 ms 足够大时,超时机制不会干扰正常业务流程,确保了异步操作的可靠性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











