promise本身不负责事件分发,而是封装状态变更的异步结果;asynceventbus用map存储latest值、resolvers队列和subscribers列表,实现同步获取、一次等待和持续监听三种状态消费模式。

用 Promise 实现发布订阅状态异步总线,核心不是靠 Promise 本身做事件分发(Promise 是一次性、不可重放的),而是用它来封装状态变更的异步结果,配合一个中心化的事件存储和触发机制。下面是一个轻量、可复用、支持“等待最新状态”和“监听后续变化”的简易实现。
状态总线基础结构:用 Map 存储 Promise 缓存 + 订阅队列
每个状态键(如 "user.login")对应:
- 一个
latest:保存最近一次 resolve 的值(用于同步读取或立即返回最新状态) - 一个
resolvers:数组,存所有 pending 的Promise.resolve回调(供后续publish触发) - 一个
subscribers:数组,存所有注册的监听函数(每次 publish 后自动通知)
这样既支持“我想要当前状态(同步)”,也支持“等下一次状态更新(异步 Promise)”,还支持“持续监听变化(回调)”。
实现 publish 和 subscribe 方法
关键逻辑如下(无依赖,纯 JS):
class AsyncEventBus {
constructor() {
this.state = new Map(); // key → { latest, resolvers: [], subscribers: [] }
}
// 发布新状态:resolve 所有等待的 Promise,并通知监听者
publish(key, value) {
const entry = this.state.get(key) || {
latest: undefined,
resolvers: [],
subscribers: []
};
entry.latest = value;
// 解决所有挂起的 Promise
entry.resolvers.forEach(resolve => resolve(value));
entry.resolvers = [];
// 通知所有订阅者(异步避免阻塞)
entry.subscribers.forEach(cb => setTimeout(() => cb(value), 0));
this.state.set(key, entry);
}
// 订阅:返回一个 Promise,只 resolve 下一次变更(类似“一次性的 await”)
subscribe(key) {
const entry = this.state.get(key) || {
latest: undefined,
resolvers: [],
subscribers: []
};
return new Promise(resolve => {
entry.resolvers.push(resolve);
this.state.set(key, entry);
});
}
// 监听:注册长期回调,每次 publish 都触发(支持取消)
listen(key, cb) {
const entry = this.state.get(key) || {
latest: undefined,
resolvers: [],
subscribers: []
};
entry.subscribers.push(cb);
this.state.set(key, entry);
// 返回取消函数
return () => {
const idx = entry.subscribers.indexOf(cb);
if (idx > -1) entry.subscribers.splice(idx, 1);
};
}
// 获取当前最新值(同步,不等待)
get(key) {
const entry = this.state.get(key);
return entry ? entry.latest : undefined;
}
}
使用示例:登录状态流控制
模拟用户登录后,多个模块等待或响应状态:
const bus = new AsyncEventBus();
// 模块 A:等待首次登录成功(Promise 语义)
bus.subscribe("auth.status").then(status => {
console.log("模块A收到:", status); // → "logged_in"
});
// 模块 B:持续监听状态变化
const off = bus.listen("auth.status", status => {
console.log("模块B监听到:", status);
});
// 模块 C:直接读取当前状态(可能为 undefined)
console.log("当前状态:", bus.get("auth.status")); // → undefined
// 模拟登录完成(触发所有)
setTimeout(() => {
bus.publish("auth.status", "logged_in");
}, 1000);
注意:subscribe 返回的是“下一次变更”的 Promise,天然支持 await bus.subscribe("x");listen 则适合 UI 组件响应式更新;get 适合初始化时快速判断。
进阶小技巧:支持默认值 & 链式 await
可以轻松扩展:
- 在
subscribe中检查entry.latest !== undefined,若已有值,立即 resolve(实现“当前或下次”语义) - 给
publish加时间戳或版本号,让监听者能过滤重复/过期更新 - 把
subscribe改造成watch(key, opts?),支持 deep、debounce 等(但这就接近 MobX/Vue 响应式了)
不复杂但容易忽略:Promise 不是事件总线,它是状态跃迁的结果容器;真正起发布订阅作用的是你维护的 resolvers 和 subscribers 列表 —— Promise 只是让“等待下一次”这件事变得自然、可组合、可 await。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











