proxy 不能直接代理 promise 实例,因为 promise 状态不可变且无法拦截其 resolve/reject;正确做法是代理返回 promise 的函数,用 apply trap 在调用时介入,实现请求拦截、执行与失败重试的完整流程。

Proxy 本身不直接处理 Promise 的异步状态变化,但它可以代理返回 Promise 的函数,在调用阶段介入,实现“请求发出前拦截 → 执行 → 失败时按策略重试”的完整流程。关键不是代理 Promise 实例,而是代理那个会生成 Promise 的行为(比如 fetch 封装函数),并在其 rejected 时触发重试逻辑。
为什么不能直接代理 Promise 实例?
Promise 是不可变的:一旦创建,其内部状态(pending → fulfilled/rejected)和结果就无法被 Proxy 拦截或修改。set、get 等 trap 对已 resolve 或 reject 的 Promise 对象无效;你无法用 Proxy “监听”它的状态变更,也无法在 catch 触发时自动再跑一次 —— 那属于 Promise 链的控制流,不在 Proxy 能力范围内。
正确做法:代理发起异步操作的函数
把重试逻辑放在函数调用入口,让 Proxy 拦截的是“执行动作”,而不是“等待结果”。这样既能保持原函数调用方式不变,又能统一注入容错能力。
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 用
applytrap 拦截函数调用,包裹原始请求逻辑 - 内部用 async/await 或 .then/.catch 处理 Promise 结果
- 若 rejected 且未达最大重试次数,则递归或循环调用自身(带退避延迟)
- 支持配置:重试次数、基础延迟、是否过滤特定错误(如 401 不重试)
一个轻量可用的实现示意
以下代码封装了一个可重试的 fetch 函数代理:
function createRetryProxy(fn, { maxRetries = 3, baseDelay = 100 } = {}) {
return new Proxy(fn, {
apply(target, thisArg, args) {
const attempt = async (n) => {
try {
return await target.apply(thisArg, args);
} catch (err) {
if (n >= maxRetries) throw err;
await new Promise(r => setTimeout(r, baseDelay * Math.pow(2, n)));
return attempt(n + 1);
}
};
return attempt(0);
}
});
}
<p>// 使用示例
const safeFetch = createRetryProxy(fetch, { maxRetries: 2 });
safeFetch('/api/data').then(console.log).catch(console.error);</p>进阶要点:与 Promise 链自然融合
代理后的函数仍返回标准 Promise,因此可无缝接入现有 Promise 流程:
- 能链式调用
.then()、.catch(),重试过程对外透明 - 可在
async/await中直接使用,语法无感 - 若需区分“原始失败”和“重试后仍失败”,可在抛出错误前附加 retryCount 字段
- 对 HTTP 错误码做判断(如 400/404 不重试,500/网络断连才重试)应在 catch 内部细化










