EventEmitter 是 NodeJS 的核心模块 events 中的类,用于对 NodeJS 中的事件进行统一管理,用 events 特定的 API 对事件进行添加、触发和移除等等,核心方法的模式类似于发布订阅
1. Node 中的 EventEmitter
EventEmitter本质上是一个观察者模式的实现。
观察者模式:它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。
1 2 3 4 5 6 7 8 9
| let events = require('events'); let eventEmitter = new events.EventEmitter();
eventEmitter.on('show', function () { console.log('this is show callback'); })
eventEmitter.emit('show');
|
eventEmitter是EventEmitter模块的一个实例,eventEmitter的emit方法,发出show事件,通过eventEmitter的on方法监听,从而执行相应的函数。
2. 简单实现一个 EventEmitter
接下来我们简单实现一个EventEmitter模块的基础功能emit和on。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| class EventEmitter { constructor () { this._events = {}; }
on (eventName, callback) { if (!this._events) { this._events = {}; } if (!this._events[eventName]) { this._events[eventName] = []; } this._events[eventName].push(callback); }
emit (eventName, ...args) { if (this._events[eventName]) { for (var i = 0; i < this._events[eventName].length; i++) { this._events[eventName][i](...args); } } }
off (eventName, callback) { if (callback) { this._events[eventName] = this._events[eventName].filter(fn => fn !== callback); } else { delete this._events[eventName]; } }
once (eventName, callback) { let onceFun = (...args) => { callback.apply(this, args); this.off(eventName, onceFun); } this.on(eventName, onceFun); } }
|
3. EventEmitter 模块的异常处理
为什么要添加异常处理模块?因为node中有一个特殊的事件error,如果异常没有被捕获,就会触发 process 的 uncaughtException 事件抛出,如果没有注册该事件的监听器,则 Node.js 会在控制台打印该异常的堆栈信息,并结束进程。
1. try…catch 方法
通过 try…catch 可以来捕获错误:
1 2 3 4 5
| try { let x = x; } catch (e) { console.log(e); }
|
如上,赋值语句的错误会被捕获,但是try…catch不能捕获非阻塞或者异步函数里的异常。
1 2 3 4 5 6 7
| try { process.nextTick(function () { let x = x; }) } catch (e) { console.log(e); }
|
如上,因为process.nextTick是异步的,因此在process.nextTick内部的错误不能被捕获。
2. process.on(‘uncaughtException’) 方法
node中提供了一个最外层的兜底的捕获异常的方法。非阻塞或者异步函数中的异常都会抛出到最外层,如果异常没有被捕获,那么会暴露出来,被最外层的process.on(‘uncaughtException’)所捕获。
1 2 3 4 5 6 7 8 9
| try { process.nextTick(function(){ let x = x; },0); } catch (e) { console.log('该异常已经被捕获'); console.log(e); } process.on('uncaughtException',function(err){console.log(err)})
|
4. EventEmitter 源码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
|
function EventEmitter () { this._events = Object.create(null); };
EventEmitter.defaultMaxListeners = 10;
EventEmitter.prototype.on = EventEmitter.prototype.addListener = function (type, listener, flag) { if (!this._events) this._events = Object.create(null); if (this._events[type]) { if (flag) { this._events[type].unshift(listener); } else { this._events[type].push(listener); } } else { this._events[type] = [listener]; } if (type !== 'newListener') { this.emit('newListener', type); } };
EventEmitter.prototype.emit = function (type, ...args) { if (this._events[type]) { this._events[type].forEach(fn => fn.call(this, ...args)); } };
EventEmitter.prototype.once = function (type, listener) { let _this = this; function only() { listener(); _this.removeListener(type, only); } only.origin = listener; this.on(type, only); };
EventEmitter.prototype.off = EventEmitter.prototype.removeListener = function (type, listener) { if (this._events[type]) { this._events[type] = this._events[type].filter(fn => { return fn !== listener && fn.origin !== listener }); } };
|