【node不完全指西】EventEmitter (事件发布/订阅模式)解析

11次阅读

共计 4160 个字符,预计需要花费 11 分钟才能阅读完成。

从 node 异步编程解决方案说起吧:

事件发布 / 订阅模式
Promise/deferred 模式
流程控制库

事件发布 / 订阅模式
事件监听器模式是一种广泛运用于异步编程的模式,是回调函数的事件话,又称发布 / 订阅模式。
主要实现的几个功能包括

on
remove
once
emit

废话少说,我们来简单的实现一个事件监听函数吧
首先创建一个 eventEmitter 函数
function EventEmitter() {
// 用 Object.create(null) 代替空对象 {}
// 好处是无杂质,不继承原型链
// _events 来保存观察着队列的信息
this._events = Object.create(null);
}
因为过多的侦听器占用大量内存,导致内存泄漏,所以侦听器的个数一般不会超过 10 个,否则会有 warnning 警告⚠️接下来是一些默认的设置
// 默认最多的绑定次数
EventEmitter.defaultMaxListeners = 10;
// 同 on 方法
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
// 返回监听的事件名
EventEmitter.prototype.eventNames = function () {
return Object.keys(this._events);
};
// 设置最大监听数
EventEmitter.prototype.setMaxListeners = function (n) {
this._count = n;
};
// 返回监听数
EventEmitter.prototype.getMaxListeners = function () {
return this._count ? this._count : this.defaultMaxListeners;
};
接下来是 on 函数的实现
EventEmitter.prototype.on = function (type, cb, flag) {
// 不是 newListener 就应该让 newListener 执行以下
if (type !== ‘newListener’) {
this._events[‘newListener’] && this._events[‘newListener’].forEach(listener => {
listener(type);
});
}
if (this._events[type]) {
// 根据传入的 flag 来决定是向前还是向后添加
if (flag) {
this._events[type].unshift(cb);
} else {
this._events[type].push(cb);
}
} else {
this._events[type] = [cb];
}
// 监听的事件不能超过了设置的最大监听数
if (this._events[type].length === this.getMaxListeners()) {
console.warn(‘ 警告 - 监听器 Number 过大 ’);
}
};
解析:on 函数是帮定的初始函数,首先判断是否是首次进行侦听,如果是的话,先进行一遍初始化函数 接下来在——events 队列里找到指针为 type 的地方,根据 flag 判断是在队列尾还是头加入 callback 函数
接下来是 once 监听一次的实现方法
// 监听一次
EventEmitter.prototype.once = function (type, cb, flag) {
// 先绑定,调用后删除
function wrap() {
cb(…arguments);
this.removeListener(type, wrap);
}
// 自定义属性
wrap.listen = cb;
this.on(type, wrap, flag);
};
解析:实现为在 callback 上包装一层 remove 操作,再当做一个新的 callback 传入 on 函数 这样的的话在首次执行回调的时候就会执行 remove 操作,达到执行一次就删除的操作
接下来是 remove 函数,删除一个 type 的侦听器
EventEmitter.prototype.removeListener = function (type, cb) {
if (this._events[type]) {
this._events[type] = this._events[type].filter(listener => {
return cb !== listener && cb !== listener.listen;
});
}
};
解析:传入 type 和要删除的 callback,对 type 标记的数组进行 filter 操作,假如 cb cb === listener 则过滤掉
删除所有
EventEmitter.prototype.removeAllListener = function () {
this._events = Object.create(null);
};
接下来是发布函数 emit
EventEmitter.prototype.emit = function (type, …args) {
if (this._events[type]) {
this._events[type].forEach(listener => {
listener.call(this, …args);
});
}
};
解析:也比较直观,如果 events 里面存在 type 的监听器队列,则队列里的每个回调都执行一遍,并且用 call 函数绑定 this 和 arg
完整代码
//EventEmitter.js

function EventEmitter() {
// 用 Object.create(null) 代替空对象 {}
// 好处是无杂质,不继承原型链的东东
this._events = Object.create(null);
}
// 默认最多的绑定次数
EventEmitter.defaultMaxListeners = 10;
// 同 on 方法
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
// 返回监听的事件名
EventEmitter.prototype.eventNames = function () {
return Object.keys(this._events);
};
// 设置最大监听数
EventEmitter.prototype.setMaxListeners = function (n) {
this._count = n;
};
// 返回监听数
EventEmitter.prototype.getMaxListeners = function () {
return this._count ? this._count : this.defaultMaxListeners;
};
// 监听
EventEmitter.prototype.on = function (type, cb, flag) {
// 默认值,如果没有_events 的话,就给它创建一个
if (!this._events) {
this._events = Object.create(null);
}
// 不是 newListener 就应该让 newListener 执行以下
if (type !== ‘newListener’) {
this._events[‘newListener’] && this._events[‘newListener’].forEach(listener => {
listener(type);
});
}
if (this._events[type]) {
// 根据传入的 flag 来决定是向前还是向后添加
if (flag) {
this._events[type].unshift(cb);
} else {
this._events[type].push(cb);
}
} else {
this._events[type] = [cb];
}
// 监听的事件不能超过了设置的最大监听数
if (this._events[type].length === this.getMaxListeners()) {
console.warn(‘ 警告 - 警告 - 警告 ’);
}
};
// 向前添加
EventEmitter.prototype.prependListener = function (type, cb) {
this.on(type, cb, true);
};
EventEmitter.prototype.prependOnceListener = function (type, cb) {
this.once(type, cb, true);
};
// 监听一次
EventEmitter.prototype.once = function (type, cb, flag) {
// 先绑定,调用后删除
function wrap() {
cb(…arguments);
this.removeListener(type, wrap);
}
// 自定义属性
wrap.listen = cb;
this.on(type, wrap, flag);
};
// 删除监听类型
EventEmitter.prototype.removeListener = function (type, cb) {
if (this._events[type]) {
this._events[type] = this._events[type].filter(listener => {
return cb !== listener && cb !== listener.listen;
});
}
};
EventEmitter.prototype.removeAllListener = function () {
this._events = Object.create(null);
};
// 返回所有的监听类型
EventEmitter.prototype.listeners = function (type) {
return this._events[type];
};
// 发布
EventEmitter.prototype.emit = function (type, …args) {
if (this._events[type]) {
this._events[type].forEach(listener => {
listener.call(this, …args);
});
}
};

module.exports = EventEmitter;

正文完
 0