78 lines
2.2 KiB
TypeScript
78 lines
2.2 KiB
TypeScript
import Disposable from "../base/disposable";
|
|
import type {
|
|
XEventEmitter as IEventEmitter,
|
|
IEventListener,
|
|
IEventName
|
|
} from "../types";
|
|
import type { IEmitterState } from "./interface";
|
|
|
|
/**
|
|
* EventEmitter class
|
|
*
|
|
* https://nodejs.dev/api/events.html
|
|
*
|
|
* https://nodejs.dev/en/learn/the-nodejs-event-emitter/
|
|
*/
|
|
export default class XEventEmitter extends Disposable implements IEventEmitter {
|
|
// private store for states
|
|
#state: IEmitterState;
|
|
|
|
constructor() {
|
|
super();
|
|
this.#state = {
|
|
stack: [],
|
|
store: new Map()
|
|
};
|
|
this.register({ dispose: () => this.#state.store.clear() });
|
|
}
|
|
|
|
public on(eventName: IEventName, listener: IEventListener): void {
|
|
const store = this.#state.store;
|
|
if (store.has(eventName)) {
|
|
store.get(eventName)?.add(listener);
|
|
} else {
|
|
store.set(eventName, new Set([listener]));
|
|
}
|
|
}
|
|
|
|
public once(eventName: IEventName, listener: IEventListener): void {
|
|
const evlistener = (...args: unknown[]) => {
|
|
listener.call(undefined, ...args);
|
|
this.off(eventName, evlistener);
|
|
};
|
|
const store = this.#state.store;
|
|
if (store.has(eventName)) {
|
|
store.get(eventName)?.add(evlistener);
|
|
} else {
|
|
store.set(eventName, new Set([evlistener]));
|
|
}
|
|
}
|
|
|
|
public off(eventName: IEventName, listener: IEventListener): void {
|
|
const all = this.#state.store.get(eventName);
|
|
if (all) {
|
|
for (const fn of all) {
|
|
if (fn === listener) {
|
|
all.delete(listener);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public emit(eventName: IEventName, ...args: unknown[]): void {
|
|
if (this.isDisposed) return;
|
|
const stack = this.#state.stack;
|
|
if (stack.includes(eventName)) return;
|
|
const listeners = this.#state.store.get(eventName);
|
|
if (listeners) {
|
|
stack.push(eventName);
|
|
for (const fn of listeners) {
|
|
fn.call(undefined, ...args);
|
|
}
|
|
stack.pop();
|
|
}
|
|
return;
|
|
}
|
|
}
|