跳到主内容

如何实现一个事件监听器 EventEmitter

· 3分钟阅读

什么是 EventEmitter?

EventEmitter 类是 Node.js 的内置类,位于 events 模块。根据文档中的描述:

大部分的 Node.js 核心 API 都是基于惯用的异步事件驱动的体系结构所实现的,在该体系结构中,某些类型的对象(称为“发射器”)发出已命名事件,这些事件会导致调用 Function 对象(“监听器”)”

EventEmitter 可以描述为发布-订阅的实现,通过 EventEmitter 可以实现事件的订阅和发布。

实现一个发布订阅功能,在大厂面试中出现的频率也是相对较高,那么本文将一步一步实现如何实现一个发布订阅功能。

EventEmitter 方法

方法功能
addListener(event, listener)新增一个新事件到数组
once(event, listener)绑定事件,只触发一次后移除
removeListener(event, listener)移除监听
setMaxListeners(n)设置最大监听数
listeners(event)返回监听数组
emit(event, [arg1], [arg2], [...])触发事件

我们先创建一个基础类

class EventEmitter {
constructor() {
this._events = Object.create(null);
this._maxListeners = 10;
}
}

addListener

addListener(event, listener) {
(this._events[event] || (this._events[event] = []))[method](listener);
return this;
}

once

监听一次 once 比较特殊,我们可以在执行监听器回调的时候,移除监听器。这里创建一个 helper 函数。

once(event, listener) {
const self = this;
function helper() {
self.removeListener(event, helper);
listener.apply(this, arguments);
}
helper.listener = listener;
this.addListener(event, helper);
return this;
}

removeListener

removeListener(event, listener) {
const listeners = this._events[event];
if (!listeners) return this;
const index = listeners.indexOf(listener);
if (index !== -1) listeners.splice(index, 1);
return this;
}

setMaxListeners

setMaxListeners(n) {
this._maxListeners = n;
return this;
}

listeners

listeners(event) {
return this._events[event] || [];
}

emit

emit(event, [arg1], [arg2], [...]) {
const listeners = this._events[event];
if (!listeners) return this;
listeners.forEach(listener => {
listener.apply(this, arguments);
});
return this;
}

最终代码

class EventEmitter {
constructor() {
this._events = Object.create(null);
this._maxListeners = 10;
}

addListener(event, listener) {
(this._events[event] || (this._events[event] = []))[method](listener);
return this;
}

once(event, listener) {
const self = this;
function helper() {
self.removeListener(event, helper);
listener.apply(this, arguments);
}
helper.listener = listener;
this.addListener(event, helper);
return this;
}

removeListener(event, listener) {
const listeners = this._events[event];
if (!listeners) return this;
const index = listeners.indexOf(listener);
if (index !== -1) listeners.splice(index, 1);
return this;
}

setMaxListeners(n) {
this._maxListeners = n;
return this;
}

listeners(event) {
return this._events[event] || [];
}

emit(event, [arg1], [arg2], [...]) {
const listeners = this._events[event];
if (!listeners) return this;
listeners.forEach(listener => {
listener.apply(this, arguments);
});
return this;
}
}