Promise实现带自动降级的异步请求,核心是主请求失败后按策略尝试缓存、备用接口或兜底数据,并统一返回结构;需用自定义错误区分可降级(如超时、502-504)与不可降级错误(如401、404),结合Promise.race控制超时,通过链式catch实现多级降级,最终封装为支持配置化参数的复用工具函数。

用 Promise 实现带自动降级的异步请求,核心是:主请求失败后,自动尝试备用方案(如缓存、简化接口、兜底数据),并统一返回结构一致的结果。
降级策略要明确,Promise 链要可控
不能只靠 catch 无差别捕获错误——得区分网络超时、服务不可用、数据格式异常等。建议用自定义错误类或错误码来判断是否可降级:
- 网络超时、502/503/504 等服务端临时错误 → 可降级
- 401(未登录)、403(权限不足)、404(资源不存在)→ 通常不降级,应原样抛出
- JSON 解析失败、字段缺失 → 视业务决定是否用默认值兜底
用 Promise.race 控制超时 + 降级触发时机
避免主请求长期挂起。把主请求和一个「超时 Promise」一起传给 Promise.race,超时就立即走降级逻辑:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
function timeout(ms, promise) {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(new Error('timeout')), ms)
)
]);
}
// 示例:主请求超时后,尝试读本地缓存
function fetchWithFallback(url, timeoutMs = 8000) {
return timeout(timeoutMs, fetch(url))
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.catch(err => {
if (err.message === 'timeout' || /50[2-4]/.test(err.message)) {
console.warn('主请求失败,启用降级:读取 localStorage 缓存');
const cached = localStorage.getItem('api_cache_' + url);
return cached ? JSON.parse(cached) : { data: [], fallback: true };
}
throw err; // 其他错误不降级,继续上抛
});
}
多级降级可用 Promise 链式 try/catch 模拟
比如:API A → 失败则试 API B → 再失败则返回静态默认数据。用 .catch() 逐层接管,每层返回新的 Promise:
立即学习“Java免费学习笔记(深入)”;
function fetchWithMultiFallback() {
return fetch('/api/v1/data')
.then(res => res.json())
.catch(() => {
console.log('v1 失败,回退到 v2');
return fetch('/api/v2/data')
.then(res => res.json())
.catch(() => {
console.log('v2 也失败,返回兜底数据');
return { items: [], status: 'fallback', timestamp: Date.now() };
});
});
}
封装成可复用工具函数,支持配置化降级行为
把重试次数、降级 URL、缓存键、兜底数据都做成参数,方便不同接口按需使用:
function createFallbackFetcher(options) {
const {
primary,
fallbacks = [],
fallbackData = null,
cacheKey,
maxRetries = 0
} = options;
function attempt(requestUrl, retryCount = 0) {
return fetch(requestUrl)
.then(res => {
if (res.ok) return res.json();
throw new Error(`HTTP ${res.status}`);
})
.catch(err => {
if (retryCount < maxRetries) {
return new Promise(resolve => setTimeout(() => resolve(attempt(requestUrl, retryCount + 1)), 500));
}
// 尝试第一个 fallback
if (fallbacks.length > 0) {
return attempt(fallbacks.shift(), 0);
}
// 最终兜底
if (cacheKey && localStorage.getItem(cacheKey)) {
return JSON.parse(localStorage.getItem(cacheKey));
}
return fallbackData;
});
}
return () => attempt(primary);
}
// 使用
const getUserData = createFallbackFetcher({
primary: '/api/user',
fallbacks: ['/api/user/backup'],
fallbackData: { id: -1, name: '游客', role: 'guest' },
cacheKey: 'user_cache'
});
getUserData().then(data => console.log(data));

















