这里有新鲜出炉的 Node.JS 入门教程,程序狗速度看过来!
Node.js 是一个基于 Chrome JavaScript 运行时建立的一个平台, 用来方便地搭建快速的 易于扩展的网络应用 · Node.js 借助事件驱动, 非阻塞 I/O 模型变得轻量和高效, 非常适合 运行在分布式设备 的 数据密集型 的实时应用
由于 nodejs 是单线程运行的,所以 nodejs 需要借助事件轮询,本篇文章主要介绍了 Node.js:events 事件模块,有兴趣的可以了解一下。
Nodejs 的大部分核心 API 都是基于异步事件驱动设计的,所有可以分发事件的对象都是 EventEmitter 类的实例。
大家知道,由于 nodejs 是单线程运行的,所以 nodejs 需要借助事件轮询,不断去查询事件队列中的事件消息,然后执行该事件对应的回调函数,有点类似 windows 的消息映射机制。至于更细的实现环节,可以另行查找资料。
下面介绍 EventEmitter 的使用。
1、监听事件和分发事件
EventEmitter 实例可以使用
或
- on
监听事件,
- addListener
方法分发事件,如下所示:
- 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 data:1
2、向事件监听回调函数传递参数
从上面的例子可以看出,
方法可以传递任意的参数集合给回调函数,需要注意的一点是 this 关键字指向的是调用 emit 方法的 EventEmiter 实例,但在箭头函数中例外,this 指向的是全局 this,因为箭头函数中的 this 是在定义时绑定。如下所示:
- emit()
- 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 也可以移除事件绑定,利用
方法解除某个事件的绑定,因此回调函数 listener 必须是命名函数,要不然找不到该函数,因为函数是引用型类型,就算函数体是一样,也不是同一个函数,如下所示:
- removeListener(eventName,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
如上结果所示,如果设置了最大监听数量,则同一事件的监听最好不要超过该最大值,否则很可能发送内存泄漏。
来源: http://www.phperz.com/article/17/0502/330205.html