nodejs之EventEmitter实现
Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。
Node.js 里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件, 一个 fs.readStream 对象会在文件被打开的时候触发一个事件。 所有这些产生事件的对象都是 events.EventEmitter 的实例。
以下简单实现:
function EventEmitter() { this.events = {} this.counts = 0 this.maxNum = 10 // 内置事件:newListener -> 事件在添加新监听器时被触发。removeListener -> 事件在接除监听器时被触发。 this.innerEvent = { NEWLISTENER: 'newListener', REMOVELISTENER: 'removeListener' } } // 为指定事件添加一个监听器到监听器数组的尾部。 function addListener(eventName, callback) { if (typeof callback !== 'function') return if (!this.events[eventName]) { if (!this._isInnerEvent(eventName)) { this.events[eventName] = [{ type: 'on', callback }] this.counts++ if (this.counts > this.maxNum) { console.warn(`目前监听器数量:${this.counts}个,监听器已经超过${this.maxNum}个`) } if (this.events[this.innerEvent.NEWLISTENER]) { this.emit(this.innerEvent.NEWLISTENER, eventName) } } else { this.events[eventName] = { type: 'on', callback } } } else { this.events[eventName].push({ type: 'on', callback }) } } EventEmitter.prototype = { _toString: function (obj) { return Object.prototype.toString.call(obj).slice(8, -1) }, _isInnerEvent: function (eventName) { return !!this.innerEvent[eventName.toUpperCase()] }, addListener: addListener, on: addListener, // 按监听器的顺序执行执行每个监听器,如果事件有注册监听返回 true,否则返回 false。 emit: function () { let arg = Array.prototype.slice.call(arguments) let eventName = arg[0] let params = arg.slice(1) if (!this._isInnerEvent(eventName)) { if (this._toString(this.events[eventName]) === 'Array' && this.events[eventName].length) { this.events[eventName].forEach(event => { let { type, callback } = event callback.apply(null, params) if (type === 'once') { this.events[evtName].splice(index, 1) } }) return true } return false } else { this.events[eventName].callback.apply(null, params) if (this.events[eventName].type === 'once') { delete this.events[eventName] } } }, // 为指定事件注册一个单次监听器,即 监听器最多只会触发一次,触发后立刻解除该监听器。 once: function (eventName, callback) { if (typeof callback !== 'function') return if (!this.events[eventName]) { if (!this._isInnerEvent(eventName)) { this.events[eventName] = [{ type: 'once', callback }] this.counts++ if (this.counts > this.maxNum) { console.warn(`目前监听器数量:${this.counts}个,监听器已经超过${this.maxNum}个`) } if (this.events[this.innerEvent.NEWLISTENER]) { this.emit(this.innerEvent.NEWLISTENER, eventName) } } else { this.events[eventName] = { type: 'once', callback } } } else { this.events[eventName].push({ type: 'once', callback }) } }, // 移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器。 removeListener: function (eventName, callback) { if (this._toString(this.events[eventName]) === 'Array') { let _events = this.events[eventName].concat() for (let i = 0; i < _events.length; i++) { if (_events[i].callback === callback) { this.events[eventName].splice(i, 1) return } } } }, // 移除所有事件的所有监听器, 如果指定事件,则移除指定事件的所有监听器。 removeAllListeners: function (eventName) { if (eventName) { if (this.events[eventName]) { delete this.events[eventName] if (!this._isInnerEvent(eventName)) { this.counts-- if (this.events[this.innerEvent.REMOVELISTENER]) { this.emit(this.innerEvent.REMOVELISTENER, eventName) } } } } else { this.events = {} this.counts = 0 } }, // 默认情况下, EventEmitters 如果你添加的监听器超过 10 个就会输出警告信息。 setMaxListeners 函数用于提高监听器的默认限制的数量。 setMaxListeners: function (num) { this.maxNum = num }, // 返回指定事件的监听器数组。 listeners: function (eventName) { if (this._toString(this.events[eventName]) === 'Array') { let _events = this.events[eventName].concat() let newArray = [] _events.forEach(item => { newArray.push(item.callback) }) return newArray } }, // 返回指定事件的监听器数量 listenerCount: function (eventName) { if (this._toString(this.events[eventName]) === 'Array') { return this.events[eventName].length } } } var eventEmit = new EventEmitter() eventEmit.on('newListener', function newListener(eventName) { console.log('>>>>newListener ---', eventName) }) eventEmit.on('removeListener', function removeListener(eventName) { console.log('>>>>removeListener ---', eventName) }) console.log(eventEmit) function event1() { console.log('event1') } eventEmit.on('event', event1) eventEmit.on('event1', event1) eventEmit.on('event', function event2() { console.log('event2') }) eventEmit.emit('event') eventEmit.emit('event1')
每一次的记录,都是向前迈进的一步