JavaScript异步熔断核心是状态机:closed(正常调用)、open(超时后拒绝请求)、half-open(试探恢复);需手动维护状态、失败计数、时间窗口及超时重置,并配合降级、超时、重试与监控实现完整容错。

JavaScript 异步错误处理中实现自动降级与熔断保护,核心在于:**捕获失败、限制重试、隔离故障、主动拒绝请求**。它不是靠单个 try/catch 完成的,而是通过状态管理 + 策略控制 + 代理封装来协同工作。
用状态机管理熔断器(Circuit Breaker)
熔断器本质是一个有三种状态的状态机:closed(闭合)、open(打开)、half-open(半开)。需手动维护状态、失败计数、时间窗口和超时重置逻辑。
- closed:正常转发请求;连续失败达到阈值(如 5 次)且在窗口期内(如 60 秒),则跳转为 open
- open:直接拒绝新请求(抛出熔断错误),不调用下游;等待固定超时(如 10 秒)后进入 half-open
- half-open:放行少量请求试探;若成功则恢复 closed;若再失败,重置计时并回到 open
可封装为一个通用函数:
function createCircuitBreaker(options = {}) {const { timeout = 10000, failureThreshold = 5, windowMs = 60000 } = options;
let state = 'closed';
let failureCount = 0;
let lastFailureTime = 0;
let halfOpenTimer = null;
const canCall = () => {
if (state === 'open') {
const now = Date.now();
if (now - lastFailureTime > timeout) {
state = 'half-open';
}
return false;
}
return true;
};
const recordSuccess = () => {
if (state === 'half-open') state = 'closed';
failureCount = 0;
};
const recordFailure = () => {
failureCount++;
lastFailureTime = Date.now();
if (failureCount >= failureThreshold && state === 'closed') {
state = 'open';
}
};
return async function call(fn, ...args) {
if (!canCall()) {
throw new Error('Circuit is OPEN: request rejected');
}
try {
const result = await fn(...args);
recordSuccess();
return result;
} catch (err) {
recordFailure();
throw err;
}
};
}
配合降级逻辑(Fallback)封装异步调用
降级不是“兜底返回空对象”,而是提供**有意义的替代行为**:缓存值、静态默认、简化版接口、本地模拟数据等。需与熔断器组合使用,且 fallback 本身也应受保护(避免 fallback 也出错导致雪崩)。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
立即学习“Java免费学习笔记(深入)”;
- 在熔断器捕获异常后,立即执行 fallback 函数(可同步或异步)
- fallback 应尽量轻量,不依赖外部服务;如有异步操作,建议加超时(如 Promise.race + setTimeout)
- 可支持多级 fallback:primary → secondary → static default
async function fetchUserDataWithFallback(userId) {
try {
return await resilientFetch(fetch, `/api/user/${userId}`);
} catch (err) {
// 降级:先查本地缓存
if ('caches' in window) {
const cache = await caches.open('user-cache');
const cached = await cache.match(`/user/${userId}`);
if (cached) return cached.json();
}
// 再降级:返回精简默认用户
return { id: userId, name: 'User', status: 'offline' };
}
}
结合超时与重试策略增强鲁棒性
熔断和降级要起效,必须前置“快速失败”。否则慢请求堆积会拖垮整个调用链。
- 所有外部异步调用都应设超时(fetch 默认无超时,需 AbortController 或 Promise.race)
- 重试仅适用于**幂等、瞬时性错误**(如网络抖动、503),不适用于业务错误(400/401)或熔断态
- 推荐指数退避重试(如 100ms → 200ms → 400ms),并限制最大次数(通常 ≤ 3)
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), ms)
),
]);
}
async function retryAsync(fn, maxRetries = 2) {
for (let i = 0; i try {
return await withTimeout(fn(), 5000);
} catch (err) {
if (i === maxRetries || !isTransientError(err)) throw err;
await new Promise(r => setTimeout(r, Math.pow(2, i) * 100));
}
}
}
监控与可观测性不能少
没有指标的熔断是盲操作。至少需记录:
- 请求总量、成功/失败/熔断/降级次数(按接口维度)
- 熔断器状态变更日志(何时 open / half-open / closed)
- 关键延迟 P95/P99,识别慢接口是否触发熔断
前端可用 performance.mark()/measure 或自定义事件上报;服务端建议接入 Prometheus + Grafana。一旦 open 率持续高于 5%,说明上游已不稳定,需及时告警并介入。

















