menu:
- events 模块作用是什么?
- events 使用方法
- 实现 EventEmitter 模块
events 模块作用
events 模块是 NodeJS 中内置的 发布与订阅 模块 events 有诸多使用场景 包括但不限于以下场景:
- 比如最常用的 Promise 内部实现就是 发布与订阅
- 日志功能(日志监听与触发事件进行记录)
- 流处理(监听流事件)
- 网络通信(监听与数据传输)
events 使用方式
events 模块中我们主要使用以下方法: on 注册并绑定事件处理函数 prependListener 注册并绑定事件处理函数(放在队头) once 注册并绑定事件处理函数 只执行一次就删除 prependOnceListener 注册并绑定事件处理函数(放在队头) 只执行一次就删除 off 解除绑定 emits 触发事件 rawListener 返回一个 事件处理函数队列 eventNames 返回所有绑定的事件名称 removeAllListeners 删除 多个或全部 事件 以及处理函数 listenerCount 计算对应事件中处理函数的个数
on 注册并绑定事件处理函数
const girl = new Girl();
const ACTION = {
EAT: 'eat',
LEARNING: 'learning',
RUNNING: 'running'
};
// 订阅
girl.on(ACTION.EAT, (food) => {
console.log(food);
});
girl.on(ACTION.EAT, (food) => {
console.log(food);
});
// 发布
girl.emit(ACTION.EAT, 'fish');
girl.emit(ACTION.EAT, 'fish');
prependListener 注册并绑定事件处理函数(放在队头)
const girl = new Girl();
const ACTION = {
EAT: 'eat',
LEARNING: 'learning',
RUNNING: 'running'
};
// 订阅
girl.prependListener(ACTION.EAT, (food) => {
console.log(food);
});
girl.prependListener(ACTION.LEARNING, (book) => {
console.log(book);
});
// 发布
girl.emit(ACTION.LEARNING, 'Math,English');
girl.emit(ACTION.EAT, 'fish');
prependOnceListener 注册并绑定事件处理函数(放在队头) 只执行一次就删除
const girl = new Girl();
const ACTION = {
EAT: 'eat',
LEARNING: 'learning',
RUNNING: 'running'
};
// 订阅
girl.prependOnceListener(ACTION.EAT, (food) => {
console.log(food);
});
girl.prependOnceListener(ACTION.LEARNING, (book) => {
console.log(book);
});
// 发布
girl.emit(ACTION.LEARNING, 'Math,English');
girl.emit(ACTION.EAT, 'fish');
girl.emit(ACTION.LEARNING, 'Math,English');
girl.emit(ACTION.EAT, 'fish');
rawListeners 返回一个 事件处理函数队列
const girl = new Girl();
const ACTION = {
EAT: 'eat',
LEARNING: 'learning',
RUNNING: 'running'
};
// 订阅
girl.on(ACTION.EAT, (food) => {
console.log(food);
});
girl.on(ACTION.LEARNING, (book) => {
console.log(book);
});
// 发布
girl.emit(ACTION.LEARNING, 'Math,English');
girl.emit(ACTION.EAT, 'fish');
console.log(girl.rawListeners(ACTION.LEARNING)); // [ [Function (anonymous)] ]
console.log(girl.rawListeners(ACTION.EAT)); // [ [Function (anonymous)] ]
eventNames 返回所有 事件队列名称
const girl = new Girl();
const ACTION = {
EAT: 'eat',
LEARNING: 'learning',
RUNNING: 'running'
};
// 订阅
girl.on(ACTION.EAT, (food) => {
console.log(food);
});
girl.on(ACTION.LEARNING, (book) => {
console.log(book);
});
// 发布
girl.emit(ACTION.LEARNING, 'Math,English');
girl.emit(ACTION.EAT, 'fish');
console.log(girl.eventNames()); // [ 'eat', 'learning' ]
removeAllListeners 删除多个或所有
const girl = new Girl();
const ACTION = {
EAT: 'eat',
LEARNING: 'learning',
RUNNING: 'running'
};
// 订阅
girl.on(ACTION.EAT, (food) => {
console.log(food);
});
girl.on(ACTION.LEARNING, (book) => {
console.log(book);
});
// 发布
girl.emit(ACTION.LEARNING, 'Math,English');
girl.emit(ACTION.EAT, 'fish');
girl.removeAllListeners([ACTION.LEARNING]);
console.log(girl.eventNames()); // [ 'eat' ]
girl.on(ACTION.EAT, (food) => {
console.log(food);
});
girl.on(ACTION.LEARNING, (book) => {
console.log(book);
});
girl.removeAllListeners(); // 清空
console.log(girl.eventNames()); // []
listenerCount 获取事件队列的 事件处理函数对象
const girl = new Girl();
const ACTION = {
EAT: 'eat',
LEARNING: 'learning',
RUNNING: 'running'
};
// 订阅
girl.on(ACTION.EAT, (food) => {
console.log(food);
});
girl.on(ACTION.LEARNING, (book) => {
console.log(book);
});
girl.on(ACTION.LEARNING, (book) => {
console.log(book);
});
console.log(girl.listenerCount(ACTION.LEARNING)); // 2
console.log(girl.listenerCount(ACTION.EAT)); // 1
EventEmitter 实现
const EVENT_NAMES = {
NEWLISTENER: 'newListener',
REMOVELISTENER: 'removeListener'
};
function EventEmitter(opts) {
EventEmitter.init.call(this, opts);
}
// 初始化
EventEmitter.init = function (opts) {
if (isVoid(this._events)) {
// 事件映射表
this._events = Object.create(null);
}
}
// 将事件映射 事件处理函数
function _addListener(type, listener, prepend) {
// 检查是否是 函数
checkListener(listener);
let events = this._events,
existsEvent = null;
// 不存在则初始化
if (isVoid(events)) {
this._events = Object.create(null);
events = this._events;
} else {
// 当存在 newListener 事件时 添加事件则需要触发 newListener
if (!isVoid(events.newListener)) {
this.emit(EVENT_NAMES.NEWLISTENER, type, listener.listener ?? listener);
events = this._events;
}
// 是否存在该事件
existsEvent = events[type];
}
// 不存在该事件
if (isVoid(existsEvent)) {
events[type] = [];
}
// 添加事件处理函数
if (prepend) {
events[type].unshift(listener);
} else {
events[type].push(listener);
}
this._events[type] = events[type];
}
// 事件移除
function _removeListener(type, listener) {
checkListener(listener);
let events = this._events;
if (isVoid(events)) return this;
// 获取 事件处理函数列表
let listeners = events[type];
if (isVoid(listeners)) return this;
listeners = listeners.filter(listenerCallback => listener !== listenerCallback);
this._events[type] = listeners;
events = this._events;
if (listeners.length === 0) {
delete this._events[type];
}
if (!isVoid(events.removeListener)) {
this.emit(EVENT_NAMES.REMOVELISTENER, type, listener);
}
}
// 一件删除多个或全部
function _removeListeners(...types) {
let events = this._events;
if (isVoid(events)) return this;
// 处理 不存在 removeListener 事件的情况
if (isVoid(events.removeListener)) {
if (types.length === 0) {
// 删除全部
this._events = Object.create(null);
} else {
for (const type of types) {
const existsKey = events[type];
if (existsKey) {
delete events[type];
removeListener.call(this, type);
}
}
const isEvents = Reflect.ownKeys(events).length > 1;
!isEvents && removeListener.call(this, EVENT_NAMES.REMOVELISTENER);
}
return this;
}
if (types.length === 0) {
this._events = Object.create(null);
events = this._events;
return this;
}
if (types.length > 0) {
for (const type of types) {
const existsKey = events[type];
if (existsKey) {
delete events[type];
removeListener.call(this, type);
}
}
const isEvents = Reflect.ownKeys(events).length > 1;
!isEvents && removeListener.call(this, EVENT_NAMES.REMOVELISTENER);
return this;
}
function removeListener(key) {
return delete this._events[key];
}
}
// 获取事件名称
function _eventNames() {
let events = this._events;
// 不存在则初始化
if (isVoid(events)) {
this._events = Object.create(null);
events = this._events;
}
return Reflect.ownKeys(events);
}
// 事件触发
function _emit(type, ...args) {
const events = this._events;
if (isVoid(events)) {
this._events = Object.create(null);
return false;
}
const listeners = events[type],
listenerLength = listeners?.length;
if (!listenerLength) return false;
for (let i = 0; i < listenerLength; i++) {
const listenerCallback = listeners[i];
// 是否为箭头函数(箭头函数指向 undefined)
// listenerCallback.apply(isFunction(listenerCallback) ? this : undefined, args);
listenerCallback.apply(this, args);
}
return true;
}
function _listeners(eventName) {
const events = this._events;
if (isVoid(events)) return [];
const evListener = events[eventName];
if (isVoid(evListener)) return [];
return arrayClone(evListener);
}
function _listenerCount(eventName) {
const listeners = _listeners.call(this, eventName);
return listeners.length;
}
// 绑定事件
EventEmitter.prototype.on = function (type, listener) {
_addListener.call(this, type, listener, false);
return this;
}
// 将事件处理函数 添加在 开头
EventEmitter.prototype.prependListener = function (type, listener) {
_addListener.call(this, type, listener, true);
return this;
}
// 绑定事件, 只执行一次
EventEmitter.prototype.once = function (type, listener) {
const oldListener = listener;
listener = (...args) => {
oldListener(...args); // 执行一次
this.off(type, listener); // 删除
}
listener.innerListener = oldListener;
_addListener.call(this, type, listener, false);
return this;
}
// 绑定事件, 只执行一次, 并放在开头
EventEmitter.prototype.prependOnceListener = function (type, listener) {
const oldListener = listener;
listener = (...args) => {
oldListener(...args); // 执行一次
this.off(type, listener); // 删除
}
listener.innerListener = oldListener;
_addListener.call(this, type, listener, true);
return this;
}
// 取消绑定
EventEmitter.prototype.off = function (type, listener) {
_removeListener.call(this, type, listener);
return this;
}
// 事件触发
EventEmitter.prototype.emit = function (type, ...args) {
return _emit.call(this, type, ...args);
}
// 获取所有事件名称
EventEmitter.prototype.eventNames = function () {
return _eventNames.call(this);
}
// 删除多个 监听器
EventEmitter.prototype.removeAllListeners = function (...args) {
if(isArray(args[0])) {
args = args[0];
}
_removeListeners.apply(this, args);
return this;
}
// 返回一个事件队列
EventEmitter.prototype.rawListeners = function (eventName) {
return _listeners.call(this, eventName);
}
// 获取对应事件队列 处理函数个数
EventEmitter.prototype.listenerCount = function (eventName) {
return _listenerCount.call(this, eventName);
}
// utils
// 检查是否为函数
function checkListener(listener) {
if (typeof listener !== 'function') {
throw new TypeError('listener is not type function');
}
}
// 判断是否为 undefined
function isVoid(value) {
return value == undefined;
}
// 克隆数组
function arrayClone(arr) {
return arr.slice();
}
// 判断是否为数组
function isArray(arr) {
return Array.isArray(arr);
}
module.exports = EventEmitter;
总结
- events 模块是 NodeJS 内置 发布与订阅模块
- 我们常用的模块有: on, once, off, emit, prependListener, prependOnceListener, rawListeners, eventNames, listenerCount, removeAllListeners