promise可模拟单次异步通知:首次publish触发所有等待subscribe的promise并缓存结果,后续subscribe立即返回;若需多次通知,可用asyncpubsub维护订阅队列并异步派发。

可以用 Promise 配合一个简单的事件队列(或缓存回调)来模拟发布-订阅的异步通知行为,但要注意:Promise 本身是**一次性、不可重放**的,所以不能直接替代传统 Pub/Sub(如 EventEmitter),但可以实现“首次订阅即等待未来某个时刻的通知”这类轻量场景——比如等待某个初始化完成、配置加载就绪、或某个全局状态首次变为 true。
核心思路:用 Promise 封装“首次触发”的通知
不维护长期订阅列表,而是让每个 subscribe() 返回一个 Promise,该 Promise 在第一次 publish() 时 resolve,并忽略后续 publish。适合“只关心第一次结果”的场景(例如等待登录完成、API token 就绪)。
简易实现(单次通知版)
下面是一个无依赖、可直接运行的实现:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
class SimpleNotify {
constructor() {
this.resolver = null;
this.isNotified = false;
this.value = undefined;
}
// 订阅:返回一个 Promise,等待首次通知
subscribe() {
if (this.isNotified) {
return Promise.resolve(this.value);
}
return new Promise(resolve => {
this.resolver = resolve;
});
}
// 发布:仅第一次生效,触发所有当前等待的订阅者
publish(value) {
if (this.isNotified) return;
this.isNotified = true;
this.value = value;
if (this.resolver) {
this.resolver(value);
this.resolver = null;
}
}
}
// 使用示例
const ready = new SimpleNotify();
// 多个地方可以订阅(即使 publish 已发生,也能立即拿到值)
ready.subscribe().then(msg => console.log('收到:', msg)); // 等待中...
setTimeout(() => {
ready.publish('系统已就绪');
}, 1000);
ready.subscribe().then(msg => console.log('又收到:', msg)); // 立即输出:又收到: 系统已就绪
支持多次订阅 + 多次通知的增强版(类 Promise + 队列)
如果需要类似 EventEmitter 的“每次 publish 都通知所有当前订阅者”,但仍想用 Promise 语义(比如 async/await 写法),可结合 Promise.resolve().then() 延迟派发,避免同步执行问题:
- 内部维护一个回调数组(subscribers)
- 每次 subscribe() 返回一个 Promise,并把 resolve 函数存入数组
- 每次 publish() 遍历数组,用 Promise.resolve().then(() => fn(value)) 异步调用每个回调
- 可选:调用后自动清理回调(一次性)或保留(多次通知)
class AsyncPubSub {
constructor() {
this.subscribers = [];
}
subscribe() {
return new Promise(resolve => {
this.subscribers.push(resolve);
});
}
publish(value) {
// 异步逐个通知,避免阻塞 & 保证执行顺序
this.subscribers.forEach(resolve => {
Promise.resolve().then(() => resolve(value));
});
}
// 可选:清空所有订阅(如用于 cleanup)
clear() {
this.subscribers.length = 0;
}
}
// 使用示例
const event = new AsyncPubSub();
event.subscribe().then(v => console.log('第一次:', v));
event.subscribe().then(v => console.log('第二次:', v));
event.publish('Hello'); // 两个 Promise 都会在微任务中 resolve
注意事项与边界情况
- Promise 不可取消:一旦 subscribe,无法取消监听(除非加 AbortSignal 包装,但会变复杂)
- 无事件名区分:上面例子是单一主题;如需多主题,可扩展为 subscribe(topic) + 内部按 topic 分 Map 存储
- 错误处理缺失:实际项目中建议在 publish 时允许传 error,订阅端用 .catch() 或统一 reject
- 内存泄漏风险:长期运行的订阅需配合 clear() 或 weak map 管理,否则订阅者无法被 GC
不复杂但容易忽略:Promise 的设计初衷不是做 Pub/Sub,它更适合表达“某个异步操作的结果”。真要健壮的发布订阅,还是推荐 EventTarget(浏览器/Node.js 14.5+)、events.EventEmitter 或成熟库如 mitt、tiny-emitter。用 Promise 实现只是在特定约束下(比如纯函数式、无依赖、只等一次)的一种轻量取巧方式。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










