EventEmitter
什么是 EventEmitter
EventEmitter 是 Node.js 中一个非常重要的模块,许多模块都继承了它。EventEmitter 的核心就是事件触发与事件监听器功能的封装。
发射器对象(EventEmitter)发出事件,这些事件会导致调用之前注册的监听器,因此,发射器对象具有两个基本功能:
- 发射事件
- 注册/注销监听器
事件注册方法
addListener(event, listener)
js
addListener(event, fn) {
this.listeners[event] = this.listeners[event] || [];
this.listeners[event].push(fn);
return this;
}
addListener 方法会检查事件是否已注册,如果是,则返回已注册的数组,否则返回一个新数组。然后将“fn”添加到数组中。
TIP
可以针对同一事件注册多个回调。
on(event, listener)
js
on(event, fn) {
return this.addListener(event, fn);
}
on 方法只是 addListener 方法的别名。
事件注销方法
removeListener(event, listener)
js
removeListener (event, fn) {
let lis = this.listeners[event];
if (!lis) return this;
for(let i = lis.length; i > 0; i--) {
if (lis[i] === fn) {
lis.splice(i,1);
break;
}
}
return this;
}
removeListener 方法会按事件获取监听器数组,然后遍历监听器数组,找到与“fn”相同的监听器,然后删除。
TIP
如果同一事件注册了多个回调,只会删除一个,其他回调不受影响。
off(event, listener)
js
off(event, fn) {
return this.removeListener(event, fn);
}
off 方法只是 removeListener 方法的别名。
事件触发方法
once(event, listener)
js
once(eventName, fn) {
this.listeners[event] = this.listeners[eventName] || [];
const onceWrapper = () => {
fn();
this.off(eventName, onceWrapper);
}
this.listeners[eventName].push(onceWrapper);
return this;
}
once 方法会注册一个只执行一次的监听器,当事件被触发时,监听器会被移除。
once 方法中创建了一个名为 onceWrapper 的包装函数,它会在触发事件时执行 fn 并移除监听器。
emit(event, ...args)
js
emit(eventName, ...args) {
let fns = this.listeners[eventName];
if (!fns) return false;
fns.forEach((f) => {
f(...args);
});
return true;
}
emit 方法会按事件注册顺序同步调用监听器数组中的每个监听器,并将提供的参数传递给每个监听器。
事件查询方法
listenerCount(event)
js
listenerCount(eventName) {
let fns = this.listeners[eventName] || [];
return fns.length;
}
listenerCount 方法返回指定事件的监听器数量。
rawListeners(event)
js
rawListeners(event) {
return this.listeners[event];
}
rawListeners 返回指定事件的监听器数组副本,如果事件已经发出一次,返回的数组中的监听器不包括 once 注册的监听器。
完整代码实现
js
class EventEmitter {
listeners = {}
addListener(eventName, fn) {
this.listeners[eventName] = this.listeners[eventName] || [];
this.listeners[eventName].push(fn);
return this;
}
on(eventName, fn) {
return this.addListener(eventName, fn);
}
once(eventName, fn) {
this.listeners[eventName] = this.listeners[eventName] || [];
const onceWrapper = () => {
fn();
this.off(eventName, onceWrapper);
}
this.listeners[eventName].push(onceWrapper);
return this;
}
off(eventName, fn) {
return this.removeListener(eventName, fn);
}
removeListener (eventName, fn) {
let lis = this.listeners[eventName];
if (!lis) return this;
for(let i = lis.length; i > 0; i--) {
if (lis[i] === fn) {
lis.splice(i,1);
break;
}
}
return this;
}
emit(eventName, ...args) {
let fns = this.listeners[eventName];
if (!fns) return false;
fns.forEach((f) => {
f(...args);
});
return true;
}
listenerCount(eventName) {
let fns = this.listeners[eventName] || [];
return fns.length;
}
rawListeners(eventName) {
return this.listeners[eventName];
}
}