const Pre = '__pre__' const Last = '__last__' export type AsyncHandler = (event: T) => any export type AsyncEvents = Record export type AsyncFlush = { pre?: boolean; last?: boolean } export type AsyncBus = { on(type: Key, handler: AsyncHandler, flush?: AsyncFlush): void off(type: Key, handler?: AsyncHandler, flush?: AsyncFlush): void emit(type: Key, args?: T[Key]): Promise } export const asyncBusFactory = () => { const store = {} as { [key in keyof T]: Array } const allKey = (type: keyof T): Array => [Pre + type.toString(), type, Last + type.toString()] const getKey = (type: keyof T, flush?: AsyncFlush): keyof T => { const keys = allKey(type) return flush ? (flush.pre ? keys[0] : flush.last ? keys[2] : keys[0]) : keys[0] } const bus: AsyncBus = { on: (type, handler, flush) => { const key = getKey(type, flush) if (!store[key]) { store[key] = [] } if (!store[key].includes(handler as any)) { store[key].push(handler as any) } }, off: (type, handler, flush) => { const keys = flush ? [getKey(type, flush)] : allKey(type) for (const key of keys) { if (handler) { if (store[key]) { store[key] = store[key].filter(h => h !== handler) } } else if (store[key]) { delete store[key] } } }, emit: async (type, args) => { const keys = allKey(type) for (const key of keys) { if (store[key]) { for (const fn of store[key]) { console.log(fn) await fn(args) } } } }, } return bus }