可通过 proxy 包裹 promise 实例拦截 then/catch/finally 方法调用及 status 等属性读取,实现自动错误捕获、状态跟踪与超时控制;但无法直接访问内部 [[promisestate]],所有状态模拟依赖外部变量与回调推断。

可以通过 Proxy 包裹 Promise 实例,拦截其属性访问(如 then、catch、finally)和状态读取(如模拟访问 status),从而添加日志、自动错误捕获、超时控制等能力。但要注意:Promise 原生实例的 [[PromiseState]] 和 [[PromiseResult]] 是内部不可枚举、不可配置的,无法直接代理状态;真正可拦截的是方法调用与属性读取行为。
拦截 then/catch/finally 实现自动错误追踪
在每次调用 then 或 catch 时注入统一错误处理逻辑,避免每个链式调用都手动写 .catch(console.error):
function instrumentedPromise(p) {
return new Proxy(p, {
get(target, prop, receiver) {
if (prop === 'then' || prop === 'catch' || prop === 'finally') {
const original = target[prop];
return function(...args) {
const result = original.apply(this, args);
// 自动附加兜底错误监听(仅对未被 catch 的 rejection 生效)
if (prop !== 'catch') {
result.catch(err => {
console.warn('[Auto-Catch]', err);
// 可上报、触发监控、重抛等
});
}
return result;
};
}
return Reflect.get(target, prop, receiver);
}
});
}
// 使用
const p = instrumentedPromise(Promise.reject(new Error('oops')));
p.then(() => {}).catch(() => {}); // 此处已有 catch,不会触发 auto-catch
p.then(() => {}); // 触发 auto-catch 日志
添加可读的状态属性(pending/fulfilled/rejected)
原生 Promise 没有公开状态字段,但可通过 Proxy 在访问 status 时返回当前状态(需配合内部状态跟踪):
function trackedPromise(p) {
let status = 'pending';
let result;
const proxy = new Proxy(p, {
get(target, prop, receiver) {
if (prop === 'status') return status;
if (prop === 'result') return result;
if (prop === 'then') {
return function(onFulfilled, onRejected) {
const wrappedFulfilled = (val) => {
status = 'fulfilled';
result = val;
return onFulfilled?.(val);
};
const wrappedRejected = (err) => {
status = 'rejected';
result = err;
return onRejected?.(err);
};
return target.then(wrappedFulfilled, wrappedRejected);
};
}
if (prop === 'catch') {
return function(onRejected) {
status = 'pending'; // catch 不改变 pending 状态,但可能消费 rejection
return target.catch((err) => {
status = 'rejected';
result = err;
return onRejected(err);
});
};
}
return Reflect.get(target, prop, receiver);
}
});
// 启动状态监听(兼容 Promise A+)
p.then(
val => { status = 'fulfilled'; result = val; },
err => { status = 'rejected'; result = err; }
);
return proxy;
}
// 使用
const tp = trackedPromise(Promise.resolve(42));
console.log(tp.status); // 'fulfilled'
console.log(tp.result); // 42
限制执行时间:给 Promise 添加超时包装
Proxy 本身不直接控制异步流程,但可结合 Promise.race 在 then 调用前注入超时逻辑:
function timeoutPromise(p, ms, message = 'Promise timed out') {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error(message)), ms)
);
const raced = Promise.race([p, timeout]);
return new Proxy(raced, {
get(target, prop, receiver) {
if (prop === 'then') {
return function(onFulfilled, onRejected) {
return target.then(onFulfilled, (err) => {
if (err.message === message) {
console.warn(`[Timeout ${ms}ms]`, p);
}
return onRejected?.(err);
});
};
}
return Reflect.get(target, prop, receiver);
}
});
}
// 使用
const slow = new Promise(resolve => setTimeout(resolve, 3000, 'done'));
const safe = timeoutPromise(slow, 1000);
safe.then(console.log).catch(console.error); // 1s 后报错
注意事项与边界
Proxy 增强 Promise 属于运行时“装饰”,不改变原 Promise 行为语义,但存在几个关键限制:
- 无法真正读取或修改内部
[[PromiseState]],所有状态模拟都依赖外部变量 +then/catch回调推断 - Proxy 返回的是新对象,不是原 Promise 实例,
instanceof Promise仍为true(因为 target 是 Promise),但自定义属性/方法不会自动继承 - 不能拦截
Promise.all、Promise.race等静态方法,需单独包装这些 API - 若 Promise 已 settle,再访问
then会同步执行回调,此时 Proxy 中的包装函数仍有效,但状态快照可能滞后
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











