promise本身无内置状态变更钩子,但可通过四种方式实现:1.用.then()/.catch()显式注册回调;2.封装observablepromise类添加监听能力;3.用async/await+try-catch捕获状态;4.全局monkey patch(不推荐生产)。

Promise 本身没有内置的“状态变更钩子”(如 onFulfilled、onRejected 的监听器),但可以通过封装或扩展方式,在 Promise 状态变为 fulfilled 或 rejected 时执行自定义逻辑。
1. 使用 .then() 和 .catch() 显式注册回调
这是最直接的方式:在链式调用中,每个 .then() 和 .catch() 都会在对应状态发生时触发。注意它们只对当前 Promise 实例生效,且仅触发一次:
const p = new Promise((resolve, reject) => {
setTimeout(() => Math.random() > 0.5 ? resolve('ok') : reject('fail'), 100);
});
p.then(
value => console.log('✅ fulfilled:', value),
reason => console.log('❌ rejected:', reason)
);
-
.then(onFulfilled, onRejected)同时监听两种状态 -
.catch(fn)等价于.then(undefined, fn),只监听 rejected - 多个
.then()可以链式添加,各自独立触发
2. 封装 Promise 类,添加状态监听能力
若需多次监听同一 Promise 的状态变更(比如日志、埋点、统一错误处理),可创建一个增强版 Promise 包装器:
class ObservablePromise extends Promise {
constructor(executor) {
let _resolve, _reject;
super((resolve, reject) => {
_resolve = resolve;
_reject = reject;
executor(resolve, reject);
});
this._handlers = { fulfilled: [], rejected: [] };
}
then(onFulfilled, onRejected) {
this._handlers.fulfilled.push(onFulfilled);
this._handlers.rejected.push(onRejected);
return super.then(onFulfilled, onRejected);
}
// 手动触发所有监听器(通常内部使用)
_notifyFulfilled(value) {
this._handlers.fulfilled.forEach(fn => fn && fn(value));
}
_notifyRejected(reason) {
this._handlers.rejected.forEach(fn => fn && fn(reason));
}
}
// 使用示例(需重写 executor 来注入通知)
const obsP = new ObservablePromise((resolve, reject) => {
setTimeout(() => {
const ok = Math.random() > 0.5;
if (ok) {
resolve('done');
obsP._notifyFulfilled('done'); // 手动通知
} else {
reject('error');
obsP._notifyRejected('error');
}
}, 100);
});
⚠️ 注意:原生 Promise 不允许外部修改状态,所以这类封装通常需要控制 executor 内部逻辑,或配合 Promise.resolve()/Promise.reject() 构造已知状态的实例再包装。
3. 利用 async/await + try-catch 捕获状态变更
在异步函数中,Promise 状态变更会自然映射为代码执行路径,是最贴近“钩子语义”的写法:
async function handleAsync() {
try {
const result = await somePromise(); // 等待 fulfilled
console.log('✅ 成功:', result);
} catch (err) {
console.log('❌ 失败:', err); // 捕获 rejected
}
}
- 适合业务层逻辑,语义清晰、可读性强
- 无法全局监听任意 Promise,但可封装成工具函数统一处理
- 结合
finally可实现“无论成功失败都执行”的钩子
4. 全局拦截:使用 Zone.js 或 monkey patch(不推荐生产)
某些高级场景(如 Angular 的 Zone.js、测试框架、性能监控)会通过劫持 Promise.prototype.then / catch 来注入全局钩子。例如:
const originalThen = Promise.prototype.then;
Promise.prototype.then = function(onFulfilled, onRejected) {
const wrappedFulfilled = onFulfilled
? (value) => { console.log('→ fulfilled'); return onFulfilled(value); }
: undefined;
const wrappedRejected = onRejected
? (reason) => { console.log('→ rejected'); return onRejected(reason); }
: undefined;
return originalThen.call(this, wrappedFulfilled, wrappedRejected);
};
- 影响所有 Promise,可能破坏依赖行为(如库内部逻辑)
- 不兼容严格模式或某些 polyfill
- 仅建议用于开发调试、监控 SDK 等受控环境
不复杂但容易忽略:Promise 是一次性状态机,状态变更后不可逆,也没有 emit/on 机制。真正可靠的“钩子”,本质是提前注册回调——要么在创建时绑定,要么在消费时用 async/await 或 .then() 显式声明。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











