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')