博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Node.js:events事件模块
阅读量:6314 次
发布时间:2019-06-22

本文共 5248 字,大约阅读时间需要 17 分钟。

Nodejs的大部分核心API都是基于异步事件驱动设计的,所有可以分发事件的对象都是EventEmitter类的实例。

大家知道,由于nodejs是单线程运行的,所以nodejs需要借助事件轮询,不断去查询事件队列中的事件消息,然后执行该事件对应的回调函数,有点类似windows的消息映射机制。至于更细的实现环节,可以另行查找资料。
下面介绍EventEmitter的使用。

1、监听事件和分发事件

EventEmitter实例可以使用onaddListener监听事件,emit()方法分发事件,如下所示:

const events = require('events'),      EventEmitter = events.EventEmitter,      util = require('util');function myEmiter(){    EventEmitter.call(this);};util.inherits(myEmiter,EventEmitter);//继承EventEmitter类const myEmitterIns = new myEmiter();myEmitterIns.on('data',(o)=>{    console.log('receive the data:'+o.a);});

或者使用class类

class myEmiter extends EventEmitter{}//继承EventEmitter类const myEmitterIns = new myEmiter();myEmitterIns.on('data',(o)=>{    console.log('receive the data:'+o.a);});myEmitterIns.emit('data',{a:1});

执行结果如下:

E:\developmentdocument\nodejsdemo>node event-example.js

receive the

2、向事件监听回调函数传递参数

从上面的例子可以看出,emit()方法可以传递任意的参数集合给回调函数,需要注意的一点是this关键字指向的是调用emit方法的EventEmiter实例,但在箭头函数中例外,this指向的是全局this,因为箭头函数中的this是在定义时绑定。如下所示:

class myEmiter extends EventEmitter{}const myEmitterIns = new myEmiter();myEmitterIns.on('data',function(data){    console.log("普通回调函数中this:");    console.log(this);});myEmitterIns.on('data1',(data1)=>{    console.log("箭头回调函数中this:");    console.log(this);});myEmitterIns.emit('data',{a:1});myEmitterIns.emit('data1',{a:1});

执行结果如下:

E:\developmentdocument\nodejsdemo>node event-example.js

普通回调函数中this:
myEmiter {
domain: null,
_events: { data: [Function], data1: [Function] },
_eventsCount: 2,
_maxListeners: undefined }
箭头回调函数中this:
{}

这里讲到箭头函数中的this,就顺便说一下,为什么箭头函数能够实现定义时绑定this,就是因为箭头函数内部根本就没有绑定this的机制,它使用的是外层作用域的this,因此它也不能作为构造函数。

3、事件监听程序的执行顺序

EventEmiter实例可以绑定多个事件,当我们顺序触发这些事件时,EventEmiter会以同步模式执行,既第一个事件处理函数没有完成,便不会触发下一个事件,如下所示:

class myEmiter extends EventEmitter{}const myEmitterIns = new myEmiter();myEmitterIns.on('data',function(data){    console.time('data事件执行了');    for(var i = 0 ; i< 100000; i++)        for(var j = 0 ; j< 100000; j++)            ;    console.timeEnd('data事件执行了');});myEmitterIns.on('data1',(data1)=>{    console.log("data1事件开始执行...");});myEmitterIns.emit('data',{a:1});myEmitterIns.emit('data1',{a:1});

执行结果如下:

E:\developmentdocument\nodejsdemo>node event-example.js

data事件执行了: 4721.401ms
data1事件开始执行...

当然我们可以在回调函数中使用异步操作,例如setTimeout,setImmediate或者process.nextTick()等,从而实现异步的效果,如下所示:

myEmitterIns.on('data',function(data){    setImmediate(()=>{        console.log('data事件执行了...');    });});

执行结果如下:

E:\developmentdocument\nodejsdemo>node event-example.js

data1事件执行了...
data事件执行了...

4、一次性事件监听

EventEmiter可以使用once监听某个事件,则该事件处理程序只会触发一次,之后emit该事件都会被忽略,因为监听程序被注销了,如下所示:

myEmitterIns.once('one',(data)=>{    console.log(data);});myEmitterIns.emit('one','this is first call!');myEmitterIns.emit('one','this is second call!');

执行结果如下:

E:\developmentdocument\nodejsdemo>node event-example.js

this is first call!

从上面的结果看出,'one'事件只执行了一次。

5、移除事件绑定

类似DOM事件监听,EventEmiter也可以移除事件绑定,利用removeListener(eventName,listener)方法解除某个事件的绑定,因此回调函数listener必须是命名函数,要不然找不到该函数,因为函数是引用型类型,就算函数体是一样,也不是同一个函数,如下所示:

myEmitterIns.on('data',function(e){    console.log(e);});myEmitterIns.removeListener('data',function(e){    console.log(e);});myEmitterIns.emit('data','hello data!');function deal(e){    console.log(e);}myEmitterIns.on('data1',deal);myEmitterIns.removeListener('data1',deal);myEmitterIns.emit('data1','hello data1!');

执行结果如下:

E:\developmentdocument\nodejsdemo>node event-example.js

hello data!
E:\developmentdocument\nodejsdemo>

从执行结果可以看出,data事件使用的是匿名函数,因此没有被移除掉,而data1事件则成功解除绑定了。这里需要注意一点的是emit触发某个事件后,所有跟该事件绑定的回调函数都会被调用,即使你在某个回调函数中使用removeListener函数移除掉另一个回调也没有用,但是随后的事件队列是移除了该回调的。如下所示:

function dealData1(e){    console.log('data事件执行了...A');}myEmitterIns.on('data',function(e){    console.log(e);    myEmitterIns.removeListener('data',dealData1);//这里解除dealData1的绑定});myEmitterIns.on('data',dealData1);myEmitterIns.emit('data','data事件执行了...B');/*执行结果为:  data事件执行了...B  data事件执行了...A*///再次触发该事件时,dealData1回调已经被解除绑定了myEmitterIns.emit('data','data事件执行了...');//data事件执行了...

另外可以使用removeAllListeners()解除所有事件的绑定。

6、获取事件监听数量和监听函数

使用emitter.listenerCount(eventName)函数获取指定事件的监听数量,函数emitter.listeners(eventName)则可以用来获取指定事件的所有监听函数,使用如下所示:

var cbA = ()=>{},    cbB = ()=>{};var emitter = new myEmiter();emitter.on('data',cbA);emitter.on('data',cbB);console.log('emitter实例的data事件绑定了%d个回调函数',emitter.listenerCount('data'));console.log('它们是:',emitter.listeners('data'));

执行结果如下:

E:\developmentdocument\nodejsdemo>node event-example.js

emitter实例的data事件绑定了2个回调函数
它们是: [ [Function: cbA], [Function: cbB] ]

7、获取和设置emitter的最大监听数量

nodejs对同一事件的监听数量建议不宜超过10个,这个可以查看EventEmitter.defaultMaxListeners属性便可得知,如下所示:

console.log(EventEmitter.defaultMaxListeners);//结果为10个

emitter通过getMaxListeners()方法获取最大监听数量以及setMaxListeners(n)方法设置最大监听数量,如下所示:

var cbA = ()=>{},    cbB = ()=>{};var emitter = new myEmiter();emitter.setMaxListeners(1);emitter.on('data',cbA);emitter.on('data',cbB);console.log(emitter.getMaxListeners());

执行结果如下:

E:\developmentdocument\nodejsdemo>node event-example.js

emitter的事件最大监听数是:1
(node:6808) Warning: Possible EventEmitter memory leak detected. 2 data listener
s added. Use emitter.setMaxListeners() to increase limit

如上结果所示,如果设置了最大监听数量,则同一事件的监听最好不要超过该最大值,否则很可能发送内存泄漏。

events模块便介绍到这。

转载于:https://www.cnblogs.com/zmxmumu/p/6098110.html

你可能感兴趣的文章
Android学习笔记--基于XMPP的即时通讯
查看>>
Thanks
查看>>
MySQL权限及登陆、退出方法
查看>>
spring4 离线doc和api(自制)
查看>>
Node学习6-fs模块
查看>>
NumPy的Matplotlib库介绍
查看>>
动态代理
查看>>
随便谈谈------计算机妹子初入测试行业之前的一些经历以及为何要选择测试行业...
查看>>
iOS开发——网络编程OC篇&(二)XMPP实现用户登录与注销
查看>>
【转】2018年EI收录中文期刊目录
查看>>
未来人类T5 安装win10,ubuntu双系统
查看>>
使用X.509数字证书加密解密实务(一)-- 证书的获得和管理
查看>>
SpringCloud 学习(二)-1 :服务注册与发现Eureka扩展
查看>>
python time,string 转换
查看>>
ASN.1探索 - 2 基础知识(3)(转)
查看>>
transition css3的问题
查看>>
MEF 编程指南(七):使用目录
查看>>
使用.NET进行高效率互联网敏捷开发的思考和探索【一、概述】
查看>>
切换默认Activity和Fragment的动画
查看>>
Android使用帧动画解决内存溢出问题
查看>>