导出可复用、可配置、可链式调用的多级重试异步请求模块:含工厂函数requestwithretry、预设策略对象、封装客户端apiclient,支持指数退避、错误过滤与promise原生集成。

直接用 export 导出一个“多级重试策略”的异步请求模块,关键不是语法本身,而是把重试逻辑封装成可复用、可配置、可导出的函数或类,并确保它天然支持 Promise 链式调用。ES6 的 export 本身不处理异步,但可以导出返回 Promise 的函数——这才是真正能被消费的“高可用异步请求模块”。
导出带策略配置的重试请求函数
把重试逻辑抽象为一个工厂函数,接收基础参数(URL、选项)和策略参数(最大重试次数、退避算法、错误过滤),返回一个可调用的 Promise 函数:
- 使用指数退避 + 全抖动(避免并发重试冲击)
- 只对 5xx 和网络类错误重试,跳过 4xx(如 401、404)
- 支持自定义 predicate 判断是否值得重试
示例代码(requestWithRetry.js):
export async function requestWithRetry(url, options = {}, strategy = {}) {
const {
maxRetries = 3,
baseDelay = 1000,
maxDelay = 10000,
predicate = (err, res) => {
return res?.status >= 500 || err instanceof TypeError || err.name === 'AbortError';
}
} = strategy;
let lastError;
for (let i = 0; i try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), options.timeout ?? 10000);
const res = await fetch(url, { ...options, signal: controller.signal });
clearTimeout(timeoutId);
if (predicate(null, res)) return res;
return res;
} catch (err) {
lastError = err;
if (i === maxRetries || !predicate(err)) throw err;
// 指数退避 + 全抖动
const delay = Math.min(baseDelay * Math.pow(2, i), maxDelay);
const jitter = Math.random() * delay;
await new Promise(r => setTimeout(r, delay + jitter));
}
}
throw lastError;
}
导出可组合的重试策略配置对象
把常用策略预设为命名导出,方便业务侧按需选用,避免重复写参数:
-
retryLight:最多 1 次重试,延迟 500ms,适合读接口 -
retryRobust:最多 3 次,指数退避+抖动,含超时控制 -
retryIdempotent:专为幂等写操作设计,含请求唯一 ID 注入
示例:
// strategies.jsexport const retryLight = { maxRetries: 1, baseDelay: 500 };
export const retryRobust = {
maxRetries: 3,
baseDelay: 1000,
maxDelay: 8000,
predicate: (err, res) => !res || res.status >= 500 || err?.name === 'TypeError'
};
export const retryIdempotent = {
...retryRobust,
beforeRequest: (options) => ({
...options,
headers: { ...options.headers, 'X-Request-ID': crypto.randomUUID() }
})
};
导出封装好的请求客户端实例
结合 Axios 或 Fetch 封装一个默认启用重试的客户端,通过 export default 提供开箱即用能力:
- 内置拦截器统一注入重试逻辑(Axios 场景)
- 导出实例而非构造函数,减少调用方心智负担
- 保留底层 request 方法供高级定制
示例(client.js):
import { requestWithRetry } from './requestWithRetry.js';
export const apiClient = {
get: (url, options, strategy) => requestWithRetry(url, { method: 'GET', ...options }, strategy),
post: (url, body, options, strategy) => requestWithRetry(
url,
{ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), ...options },
strategy
),
requestWithRetry // 暴露原始函数,便于深度定制
}
export default apiClient;
使用时按需导入,语义清晰
业务文件中无需关心重试实现细节,只需选择策略、发起请求:
// userPage.jsimport apiClient, { retryRobust } from './client.js';
async function loadUserProfile() {
try {
const res = await apiClient.get('/api/user/123', {}, retryRobust);
return await res.json();
} catch (err) {
console.error('加载用户失败,已重试 3 次', err);
throw err;
}
}










