EventEmitter
函数签名
typescript
function EventEmitter() { ... }点击查看源码
js
/**
* 确保传入的方法只能被执行一次
*
* @param {(...args: any) => any} func - 要执行的方法。
* @returns {(...args: any) => any} 返回一个新的方法,该方法只会执行一次
*/
function once(fn) {
// 利用闭包判断函数是否执行过
let called = false;
return function (...args) {
if (!called) {
called = true;
return fn.apply(this, args);
}
};
}
/**
* 一个简单的事件发射器类,用于实现发布-订阅模式
*/
export class EventEmitter {
/** 存储所有事件及其对应的监听函数 */
events;
constructor() {
this.events = new Map();
}
/**
* 为指定事件添加监听器
* @param {string} eventName - 要监听的事件名称
* @param {Function} callback - 事件触发时要调用的回调函数
* @returns {Function} 返回一个用于取消订阅的函数
*/
on(eventName, callback) {
const callbacks = this.events.get(eventName) ?? [];
this.events.set(eventName, [...callbacks, callback]);
return () => once(this.off.bind(this))(eventName, callback);
}
/**
* 为指定事件添加一次性监听器,触发后自动移除
* @param {string} eventName - 要监听的事件名称
* @param {Function} callback - 事件触发时要调用的回调函数
* @returns {Function} 返回一个用于取消订阅的函数
*/
once(eventName, callback) {
const wrapper = (...args) => {
callback(...args);
this.off(eventName, wrapper);
};
return this.on(eventName, wrapper);
}
/**
* 移除指定事件的特定监听器
* @param {string} eventName - 事件名称
* @param {Function} callback - 要移除的监听器函数
*/
off(eventName, callback) {
const callbacks = this.events.get(eventName);
if (!callbacks) return;
const index = callbacks.indexOf(callback);
index !== -1 && callbacks.splice(index, 1);
callbacks.length === 0 && this.events.delete(eventName);
}
/**
* 移除指定事件的所有监听器,如果没有指定事件名称则移除所有事件的监听器
* @param {string} [eventName] - 可选的事件名称
*/
removeAllListeners(eventName) {
if (eventName) {
this.events.delete(eventName);
} else {
this.events.clear();
}
}
/**
* 触发指定事件,调用所有监听该事件的回调函数
* @param {string} eventName - 要触发的事件名称
* @param {...any} args - 传递给监听器的参数
*/
emit(eventName, ...args) {
const callbacks = this.events.get(eventName);
if (!callbacks) return;
// 创建回调函数数组的副本,防止回调函数中的操作影响遍历
const callbacksCopy = [...callbacks];
callbacksCopy.forEach((callback) => {
try {
callback(...args);
} catch (error) {
console.error(`Error in event handler for ${eventName}:`, error);
}
});
}
}ts
export type AnyFunction = (...args: any) => any;
/**
* 确保传入的方法只能被执行一次
*
* @param {(...args: any) => any} func - 要执行的方法。
* @returns {(...args: any) => any} 返回一个新的方法,该方法只会执行一次
*/
function once<F extends AnyFunction>(fn: F) {
// 利用闭包判断函数是否执行过
let called = false;
return function (this: unknown, ...args: Parameters<F>) {
if (!called) {
called = true;
return fn.apply(this, args);
}
};
}
/**
* 一个简单的事件发射器类,用于实现发布-订阅模式
*/
export class EventEmitter<T extends string> {
/** 存储所有事件及其对应的监听函数 */
private events: Map<T, AnyFunction[]>;
constructor() {
this.events = new Map();
}
/**
* 为指定事件添加监听器
* @param {string} eventName - 要监听的事件名称
* @param {Function} callback - 事件触发时要调用的回调函数
* @returns {Function} 返回一个用于取消订阅的函数
*/
on(eventName: T, callback: AnyFunction): () => void {
const callbacks = this.events.get(eventName) ?? [];
this.events.set(eventName, [...callbacks, callback]);
return () => once(this.off.bind(this))(eventName, callback);
}
/**
* 为指定事件添加一次性监听器,触发后自动移除
* @param {string} eventName - 要监听的事件名称
* @param {Function} callback - 事件触发时要调用的回调函数
* @returns {Function} 返回一个用于取消订阅的函数
*/
once(eventName: T, callback: AnyFunction): () => void {
const wrapper = (...args: any[]) => {
callback(...args);
this.off(eventName, wrapper);
};
return this.on(eventName, wrapper);
}
/**
* 移除指定事件的特定监听器
* @param {string} eventName - 事件名称
* @param {Function} callback - 要移除的监听器函数
*/
off(eventName: T, callback: AnyFunction): void {
const callbacks = this.events.get(eventName);
if (!callbacks) return;
const index = callbacks.indexOf(callback);
index !== -1 && callbacks.splice(index, 1);
callbacks.length === 0 && this.events.delete(eventName);
}
/**
* 移除指定事件的所有监听器,如果没有指定事件名称则移除所有事件的监听器
* @param {string} [eventName] - 可选的事件名称
*/
removeAllListeners(eventName?: T): void {
if (eventName) {
this.events.delete(eventName);
} else {
this.events.clear();
}
}
/**
* 触发指定事件,调用所有监听该事件的回调函数
* @param {string} eventName - 要触发的事件名称
* @param {...any} args - 传递给监听器的参数
*/
emit(eventName: T, ...args: any[]): void {
const callbacks = this.events.get(eventName);
if (!callbacks) return;
// 创建回调函数数组的副本,防止回调函数中的操作影响遍历
const callbacksCopy = [...callbacks];
callbacksCopy.forEach((callback) => {
try {
callback(...args);
} catch (error) {
console.error(`Error in event handler for ${eventName}:`, error);
}
});
}
}如有错误,请提交issue :::