Promise实现异步重试与降级的核心是封装自动重试(含指数退避)并在超限后执行fallback;需控制次数、延迟、超时与取消,推荐分层组合timeout/retry/fallback策略。

用 Promise 实现异步重试与降级,核心是封装一个能自动重试失败请求、并在达到最大重试次数后执行备用逻辑(降级)的函数。关键在于控制重试间隔、捕获错误、避免无限循环,并在必要时切换到兜底方案。
基础重试函数(带指数退避)
重试不是简单地反复调用,而是要加延迟、限制次数,并逐步拉长等待时间(避免雪崩)。以下是一个通用 retry 函数:
function retry(fn, options = {}) {
const { maxRetries = 3, baseDelay = 100, maxDelay = 3000 } = options;
<p>return function (...args) {
let attempt = 0;</p><pre class="brush:php;toolbar:false;">const execute = () => {
return fn(...args)
.catch(err => {
attempt++;
if (attempt > maxRetries) throw err; // 超限,抛出最终错误
const delay = Math.min(baseDelay * Math.pow(2, attempt - 1), maxDelay);
return new Promise(resolve => setTimeout(resolve, delay))
.then(() => execute()); // 递归重试
});
};
return execute();}; }
使用示例:
const fetchWithRetry = retry(fetch, { maxRetries: 3, baseDelay: 200 });
<p>fetchWithRetry('/api/data')
.then(res => res.json())
.catch(err => console.error('彻底失败:', err));</p>加入降级逻辑(fallback)
当重试全部失败后,不直接报错,而是执行一个替代操作(如返回缓存数据、静态默认值或调用备用接口):
function retryWithFallback(fn, fallback, options = {}) {
const { maxRetries = 3, baseDelay = 100 } = options;
<p>return function (...args) {
let attempt = 0;</p><pre class="brush:php;toolbar:false;">const execute = () => {
return fn(...args)
.catch(err => {
attempt++;
if (attempt > maxRetries) {
// 触发降级:执行 fallback(它本身也应返回 Promise)
return Promise.resolve().then(() => fallback(...args));
}
const delay = baseDelay * Math.pow(2, attempt - 1);
return new Promise(r => setTimeout(r, delay)).then(execute);
});
};
return execute();}; }
示例:网络请求失败时返回本地缓存
const apiCall = () => fetch('/api/user').then(r => r.json());
const cachedFallback = () => Promise.resolve({ id: 1, name: '游客', isOnline: false });
<p>const robustFetch = retryWithFallback(apiCall, cachedFallback, { maxRetries: 2 });</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill6235" title="Java Maven Code Review"><img
src="https://img.php.cn/upload/skill/000/000/081/179084711841712.jpg" alt="Java Maven Code Review" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill6235" title="Java Maven Code Review" class="overflowclass">Java Maven Code Review</a>
<p class="overflowclass">审查Java Maven项目(ZIP压缩包或GitLab仓库URL),检查代码规范、命名、模块边界、可维护性问题以及重复代码。</p>
</div>
<a rel="nofollow" href="/xiazai/skill6235" title="Java Maven Code Review" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><p>robustFetch().then(data => console.log(data)); // 成功则用 API,失败两次后用缓存</p>支持取消与超时(增强健壮性)
真实场景中还需防止单次请求卡死,可组合 Promise.race 加入超时控制,并允许外部中断:
- 用 AbortController 可取消 fetch(现代浏览器支持)
- 手动超时:包装原始 Promise,和一个定时 reject 的 Promise 竞速
- 把超时、取消、重试、降级四层逻辑分层组合,而非堆在一个函数里
简易超时包装示例:
function withTimeout(promise, ms) {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(new Error(`Timeout after ${ms}ms`)), ms)
)
]);
}
<p>// 组合使用:
const fetchWithTimeoutAndRetry = retry(
() => withTimeout(fetch('/api/data'), 5000),
{ maxRetries: 2 }
);</p>实际项目中的建议结构
不要把所有策略硬编码进一个函数。推荐分层设计:
- 最底层:纯业务请求函数(如 api.getUser(id)),只负责发请求
- 中间层:按需套 retry / timeout / fallback,例如 retry(api.getUser, {…})
- 最上层:组件或服务中调用,并处理最终成功/失败(比如展示 loading、error toast、降级 UI)
- 降级函数本身也应是幂等、快速、无副作用的(别让它又去发网络请求)
这样既灵活又易测试,也能根据不同接口配置不同策略(如支付接口重试更谨慎,列表接口可更快降级)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










