JavaScript中柯里化实现限流重试的核心是封装重试逻辑、失败兜底与节流控制三者耦合关系,使调用方只关注业务函数和策略,不感知时序调度;通过闭包保存状态、返回Promise保证兼容性,并支持组合式分离关注点。

JavaScript 中用柯里化实现前端限流重试机制,核心不是单纯“把函数变多参数”,而是利用柯里化封装**重试逻辑、失败兜底、节流控制**三者耦合关系,让调用方只关心业务函数和重试策略,不感知底层时序调度。
柯里化 + 重试策略封装
先定义一个可配置的重试柯里化函数:它接收原始请求函数、最大重试次数、延迟间隔(支持函数动态计算),返回一个“已预设策略”的新函数。
- 每次调用该函数,都自动按策略执行或重试,失败时递归调用自身(带次数递减)
- 用闭包保存当前重试次数、延迟时间等状态,避免依赖外部变量
- 返回 Promise,保持调用链兼容性(可 await、可 .then)
const retry = (fn, maxRetries = 3, baseDelay = 1000) => {
return function curried(...args) {
return fn(...args)
.catch(err => {
if (maxRetries
setTimeout(() => resolve(), baseDelay)
).then(() => curried(...args));
});
};
};
<p>// 使用:fetchUser 自动带 3 次重试
const fetchUserWithRetry = retry(fetchUser, 3, 2000);
fetchUserWithRetry(123).then(data => console.log(data));
</p>
柯里化 + 节流控制(限流)
限流不是防抖或节流的简单复用,而是对“重试发起行为”本身做频率限制——比如 5 秒内最多触发 2 次重试请求。这需要在柯里化函数中维护时间窗口和计数器。
- 用闭包缓存最近请求时间戳和次数,每次调用前检查是否超限
- 超限时返回 rejected Promise 或排队(需配合队列),不立即执行也不盲目重试
- 柯里化让限流参数(窗口大小、最大请求数)在初始化时固化,调用时不重复传
const limitedRetry = (fn, maxRetries = 3, baseDelay = 1000, windowMs = 5000, maxPerWindow = 2) => {
let lastReset = Date.now();
let count = 0;
<p>return function curried(...args) {
const now = Date.now();
if (now - lastReset > windowMs) {
lastReset = now;
count = 0;
}
if (count >= maxPerWindow) {
return Promise.reject(new Error('Rate limit exceeded'));
}
count++;</p><pre class="brush:php;toolbar:false;">return fn(...args)
.catch(err => {
if (maxRetries setTimeout(r, baseDelay))
.then(() => curried(...args));
});}; };
组合柯里化:分离关注点
真正实用的写法是把限流、重试、错误分类处理拆成独立柯里化高阶函数,再用函数组合(compose)拼装,提升复用性和可测性。
- throttle(fn, windowMs, max) → 返回限流版 fn
- retryOn(fn, predicate, max) → 只对满足 predicate 的错误重试(如网络错误)
- 最终:
compose(throttle(...), retryOn(...))(fetchApi) - 每个函数只做一件事,且都支持柯里化预设参数,组合后仍是一个可调用函数
注意边界与真实场景适配
纯柯里化实现简洁,但生产环境需补充关键细节:
- 重试应区分错误类型:401(token 过期)应刷新 token 后重试,500 才走延迟重试,不能一概而用固定策略
- 限流需考虑“重试请求”是否计入配额:通常应计入,否则可能绕过限流
- 取消机制不可少:Promise.race + AbortController 防止用户离开页面后仍在后台重试
- 日志与监控:每次重试/限流拦截都应打点,便于定位稳定性问题
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











