设计模式之单例+发布订阅模式
interface Callback<T extends any[] = any[]> {
(...args: T): void
}
class Eventbus {
private events: Record<string, Set<Callback>> = {}
private static instance: Eventbus
private constructor() {}
static getInstance(): Eventbus {
return (Eventbus.instance ??= new Eventbus())
}
private validateEventName(eventName: string): void {
if (!eventName) {
throw new Error('事件名称必须是非空字符串')
}
}
on<T extends any[]>(eventName: string, cb: Callback<T>): void {
this.validateEventName(eventName)
try {
;(this.events[eventName] ??= new Set()).add(cb as Callback)
} catch (error) {
console.error(`为事件-"${eventName}"-注册回调时出错:`, error)
}
}
emit<T extends any[]>(eventName: string, ...args: T): void {
this.validateEventName(eventName)
const callbacks = this.events[eventName]
if (callbacks) {
callbacks.forEach((cb) => {
try {
cb(...args)
} catch (error) {
console.error(`对事件-"${eventName}"-执行回调时出错:`, error)
}
})
}
}
off<T extends any[]>(eventName: string, cb: Callback<T>): void {
this.validateEventName(eventName)
const callbacks = this.events[eventName]
if (callbacks && callbacks.has(cb)) {
callbacks.delete(cb)
if (callbacks.size === 0) {
delete this.events[eventName]
}
}
}
once<T extends any[]>(eventName: string, cb: Callback<T>): void {
this.validateEventName(eventName)
const handler: Callback<T> = (...args: T) => {
try {
cb(...args)
} catch (error) {
console.error(`对事件-"${eventName}"-执行一次性回调时出错:`, error)
} finally {
this.off(eventName, handler)
}
}
this.on(eventName, handler)
}
}
export const eventbus = Eventbus.getInstance()
页面使用
eventbus.on('add', () => {})