一、Node事件订阅发布1、EventEmitterNode中的很多模块都可以使用EventEmitter。有了EventEmitter才能方便的进行事件监听。让我们看看如何在Node.js中使用EventEmitter。(1)基本使用EventEmitter是对事件触发和事件监听功能的封装。在node.js中的事件模块中,事件模块中只有一个对象,就是EventEmitter。下面是最基本的使用方法:varEventEmitter=require('events').EventEmitter;varevent=newEventEmitter();event.on('some_event',function(){console.log('some_event事件触发');});setTimeout(function(){event.emit('some_event');},1000);上面的代码中,首先实例化了一个EventEimitter对象,然后就可以监听并发布事件了。通过on方法监听具体事件,通过emit方法发布事件。1秒后发布一个“some_event”事件。此时on会自动监听到事件对象,并触发相应的回调方法。(2)EventEmitter支持的方法EventEmitter实例对象支持的方法列表如下:emitter.on(name,f)//为事件名指定监听函数femitter.once(name,f)//类似到on方法,但是监听函数f是一次性的,用完会自动移除。emitter.listeners(name)//返回一个数组,其成员为事件名的所有监听函数emitter.removeListener(name,f)//移除事件名(name)的监听函数femitter.removeAllListeners//移除所有监听事件名称的函数...同时,事件发布的emit方法可以传入多个参数,第一个参数为定义的事件,其他参数会作为参数传递到该事件的回调函数中听众。2.自定义EventEmitter为了更容易理解其内部监听事件实现的原理,封装了一个模块如下:functionEventEmitter(){this._events={};//初始化一个私有属性}//type绑定事件名//监听事件监听函数EventEmitter(){this._events={};//初始化一个私有属性}//类型绑定事件名//监听事件监听EventEmitter.prototype.on=EventEmitter.prototype.addListener=函数(类型,监听器){如果(this._events[type]){this._events[type].push(监听器);}else{this._events[type]=[listener];}};EventEmitter.prototype.once=function(type,listener){functioncallOnce(){listener.apply(this,arguments);this.removeListener(type,callOnce);}this.on(type,callOnce);};EventEmitter.prototype.emit=function(type){varcallbacks=this._events[type];varargs=Array.prototype.slice.call(arguments,1);变种自我=这个;callbacks.forEach(function(callback){callback.apply(self,args);})};EventEmitter.prototype.removeListener=function(type,listener){if(this._events[t类型]){varlisteners=this._events[type];for(vari=0;i{console.log(a,b,this);//print:ab{}});myEmitter.emit('事件','a','b');(2)异步和同步EventEmitter会按照注册的顺序同步调用所有的监听器。因此,您需要确保事件的正确排序并避免竞争条件或逻辑错误。侦听器函数可以使用setImmediate()或process.nextTick()方法切换到异步操作模式:constmyEmitter=newMyEmitter();myEmitter.on('event',(a,b)=>{setImmediate(()=>{console.log('这是异步发生的');});});myEmitter.emit('event','a','b');(3)error事件当EventEmitter实例发生错误时,它会触发一个'error'事件。这是Node.js中的一个特例。如果EventEmitter没有为'error'事件注册至少一个侦听器,那么当'error'事件触发时,将抛出错误,打印堆栈跟踪,然后Node.js进程退出。constmyEmitter=newMyEmitter();myEmitter.emit('error',newError('whoops!'));//抛出错误并使Node.js崩溃为了防止Node.js进程崩溃,可以使用domain模块。(请注意,域模块已弃用。)作为最佳实践,应始终为“错误”事件注册侦听器。constmyEmitter=newMyEmitter();myEmitter.on('error',(err)=>{console.error('有错误');});myEmitter.emit('error',newError('哎呀!'));//打印:错误(4)emitter.removeListener添加于:v0.1.26eventNamelistener从名为eventName的事件的侦听器数组中移除指定的侦听器。constcallback=(stream)=>{console.log('Connection!');};server.on('connection',callback);//...server.removeListener('connection',callback);removeListenerAt大多数侦听器实例将从侦听器数组中删除。如果将任何单个侦听器多次添加到指定eventName的侦听器数组,则必须多次调用removeListener以删除每个实例。注意,一旦一个事件被触发,所有绑定到它的监听器都会被顺序触发。这意味着任何removeListener()或removeAllListeners()调用都不会在事件触发后但在最后一个侦听器完成执行之前将它们从emit()中移除。随后的事件按预期发生。constmyEmitter=newMyEmitter();constcallbackA=()=>{console.log('A');myEmitter.removeListener('event',callbackB);};constcallbackB=()=>{console.log('B');};myEmitter.on('event',callbackA);myEmitter.on('event',callbackB);//callbackA移除监听器callbackB,但是它仍然会被调用。//触发是内部监听数组为[callbackA,callbackB]myEmitter.emit('event');//打印//A//B//callbackB被移除。//内部监听器数组是[callbackA]myEmitter.emit('event');//print://A因为监听器是使用内部数组管理的,所以调用它会在监听器移除后改变注册的任何监听器的位置索引。虽然这不会影响调用侦听器的顺序,但这意味着需要重新创建emitter.listeners()方法返回的侦听器数组的副本。返回一个可以链接的EventEmitter引用