【node不完全指西】EventEmitter(事件发布/订阅模式)解析-考拉阅读前端团队-SegmentFault思否
程序员文章站
2022-04-22 15:26:43
从node异步解决方案说起吧:
事件发布/订阅模式
promise/deferred模式
流程控制库
事件发布/订阅模式
事件监听器模式是一种广泛运用于异步编程的模式,是回调函...
从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;
我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/dev...