核心是将异步控制权交还调度者,监听器须返回 promise,emit 主动管理执行流:支持并行(promise.allsettled)、串行(for...of+await)、混合策略;内置错误隔离、safecall 封装、fallback 降级;接入 signal/timeout 控制;泛型约束事件类型,weakmap 管理引用,提供 destroy 清理。

核心不是让事件总线“支持 async”,而是把异步控制权交还给调度者——你决定等不等、怎么等、等多久、错在哪、要不要停。
监听器必须返回 Promise,但 emit 要主动管理执行流
注册时不限制函数是否 async,但触发时需统一按 Promise 处理:
- 并行执行(多数场景):用 Promise.allSettled() 而非 Promise.all(),避免单个失败中断全部
- 串行执行(状态强依赖):用 for...of + await,逐个等待并捕获每个监听器错误
- 混合策略:对关键监听器设为串行,其余并行,通过分组或标签区分
内置错误隔离与降级能力
每个监听器的异常不应影响其他监听器,也不该让 emit 报错中断上层逻辑:
- 封装 safeCall(fn, ...args):内部 try/catch,返回 { success: true/false, value/error } 结构
- emit 返回统一结果数组,含每个监听器的执行状态和输出,供上层做聚合判断
- 支持 fallback 监听器:当主链超时或失败时,自动触发备用逻辑(如写日志、发告警、兜底响应)
接入取消信号与超时控制
真实调度中常需“及时止损”,比如用户退出、请求被中止、任务过期:
- emit 接收可选 { signal, timeout } 参数
- 每个监听器调用前检查 signal.aborted,已中止则跳过
- 用 Promise.race([fn(), new Promise((_, rej) => setTimeout(() => rej(new Error('timeout')), timeout))]) 包裹调用
- 超时错误不抛出,而是归入 safeCall 的 error 字段,保持流程可控
类型安全 + 生命周期闭环
长期运行的网关组件最怕内存泄漏和类型错配:
- 用泛型约束事件名与参数:如 type Events = { 'auth:verify': [token: string]; 'log:write': [msg: string, level: 'info' | 'error'] }
- on/once/emit 方法均带泛型推导,TS 可校验参数数量、类型、顺序
- off 必须精确匹配 listener 引用,推荐用 WeakMap 存储 listener → handler 映射,避免强引用滞留
- 提供 destroy() 方法:清空当前实例所有监听器,并 abort 所有未完成的 pending promise(配合 AbortController)
不复杂但容易忽略——async/await 不是终点,而是把调度逻辑从“发完即弃”变成“全程可察、可断、可溯”的起点。











