HumanBreak/src/core/common/eventEmitter.ts

168 lines
4.5 KiB
TypeScript
Raw Normal View History

2023-10-22 12:05:06 +08:00
import { has } from '@/plugin/utils';
2023-06-04 23:06:56 +08:00
export interface EmitableEvent {
[event: string]: (...params: any) => any;
}
interface Listener<T extends (...params: any) => any> {
fn: T;
once?: boolean;
2023-06-28 22:48:15 +08:00
immediate?: boolean;
2023-06-04 23:06:56 +08:00
}
interface ListenerOptions {
once: boolean;
2023-06-28 22:48:15 +08:00
immediate: boolean;
2023-06-04 23:06:56 +08:00
}
export class EventEmitter<T extends EmitableEvent = {}> {
private events: {
[P in keyof T]?: Listener<T[P]>[];
} = {};
2023-06-28 22:48:15 +08:00
private emitted: (keyof T)[] = [];
2023-06-04 23:06:56 +08:00
/**
*
* @param event
* @param fn
* @param options
*/
on<K extends keyof T>(
event: K,
fn: T[K],
options?: Partial<ListenerOptions>
) {
2023-06-28 22:48:15 +08:00
if (options?.immediate && this.emitted.includes(event)) {
fn();
if (!options.once) {
this.events[event] ??= [];
this.events[event]?.push({
fn
});
}
return;
}
2023-06-04 23:06:56 +08:00
this.events[event] ??= [];
this.events[event]?.push({
fn,
once: options?.once
});
}
/**
*
* @param event
* @param fn
*/
off<K extends keyof T>(event: K, fn: T[K]) {
const index = this.events[event]?.findIndex(v => v.fn === fn);
if (index === -1 || index === void 0) return;
this.events[event]?.splice(index, 1);
}
/**
*
* @param event
* @param fn
*/
once<K extends keyof T>(event: K, fn: T[K]) {
this.on(event, fn, { once: true });
}
/**
*
* @param event
* @param params
*/
emit<K extends keyof T>(event: K, ...params: Parameters<T[K]>) {
2023-06-28 22:48:15 +08:00
if (!this.emitted.includes(event)) {
this.emitted.push(event);
}
2023-06-04 23:06:56 +08:00
const events = (this.events[event] ??= []);
for (let i = 0; i < events.length; i++) {
const e = events[i];
e.fn(...(params as any));
if (e.once) {
events.splice(i, 1);
i--;
}
}
}
/**
*
*/
removeAllListeners(): void;
/**
*
* @param event
*/
removeAllListeners(event: keyof T): void;
removeAllListeners(event?: keyof T) {
if (has(event)) this.events[event] = [];
else this.events = {};
}
}
type IndexedSymbol = number | string | symbol;
export class IndexedEventEmitter<
T extends EmitableEvent
> extends EventEmitter<T> {
private fnMap: {
[P in keyof T]?: Map<IndexedSymbol, T[P]>;
} = {};
/**
*
* @param event
* @param symbol
* @param fn
* @param options
*/
onIndex<K extends keyof T>(
event: K,
symbol: IndexedSymbol,
fn: T[K],
options: Partial<ListenerOptions>
) {
const map = this.ensureMap(event);
if (map.has(symbol)) {
console.warn(
`监听${String(event)}出错:已存在标识符为${String(
symbol
)}`
);
this.offIndex(event, symbol);
}
map.set(symbol, fn);
this.on(event, fn, options);
}
/**
*
* @param event
* @param symbol
* @param fn
*/
onceIndex<K extends keyof T>(event: K, symbol: IndexedSymbol, fn: T[K]) {
this.onIndex(event, symbol, fn, { once: true });
}
/**
*
* @param event
* @param symbol
*/
offIndex<K extends keyof T>(event: K, symbol: IndexedSymbol) {
const map = this.ensureMap(event);
const fn = map.get(symbol);
if (!fn) return;
this.off(event, fn);
}
private ensureMap<K extends keyof T>(event: K) {
return this.fnMap[event] ?? new Map<IndexedSymbol, T[K]>();
}
2023-06-04 23:06:56 +08:00
}