Node.js 所有的异步I/O操作在完成是都会发送一个事件到事件队列。
Node.js 里面的许多对象都会分发事件:一个net.Server对象会在每次有新连接时触发一个事件,一个fs.resaStream对象会在文件被打开的时候触发一个事件。所有这些产生事件的对象都是events.EventEmitter的实例。
7-1EventEmitter类
events模块只提供了一个对象:events.EventEmitter。
EventEmitter的核心就是事件触发
与事件监听器功能
的封装。
可以通过require('events')来访问该模块
//引入 events 模块
var events = require('events');
//创建eventEmitter对象
var eventEmitter = new events.EventEmitter();
EventEmitter 对象如果在实例化时发生错误,会触发error事件。
当添加新的监听器时,newListener 事件会触发。
当监听器被移除时,removeListener事件会被触发。
下面咱们来看一个例子:
//event.js 文件
var EventEmitter = require('events').EventEmitter;
var event = new EventEmitter();
event.on('some_event', function() {
console.log('some_event 事件触发');
});
setTimeOut(function() {
event.emit('some_event')
}, 1000);
执行结果:
node event.js
some_event 事件触发
运行这段代码,1秒后控制台输出了some_evnet 事件触发
。
其原理是event对象注册了事件some_event
的一个监听器,
然后我们通过setTimeout在1秒后向event对象发送事件some_event,此时会调用some_event的监听器。
EventEmitter的每个事件有一个事件名
和若干个参数
组成。
事件名:是一个字符串,有一定的语义化
对于每个事件,EventEmitter支持若干个事件监听器。
当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递
那么我们来看一个例子:
//event1.js
var events = require('events');
var emitter = new events.EventEmitter();
emitter.on('someEvent',function(arg1,arg2){
console.log('listener1',arg1,arg2)
});
emitter.on('someEvent',function(arg1,arg2){
console.log('listener2',arg1,arg2)
});
emitter.emit('someEvent','参数1','参数2');
运行结果:
node event1.js
listener1 参数1 参数2
listener2 参数1 参数2
从上面这个例子来看:
emitter为事件someEvent注册了两个事件监听器,
然后出发了someEvent事件。
EventEmitter提供了多个属性,如on
和emit
- on函数:用于绑定事件函数
- emit:用于触发一个事件
那么EventEmitter都有哪些属性呢?
7-2方法
1.addListener(event,listener) //为指定事件添加一个监听器到监听器数组的尾部
2.on(event,listener) //为指定事件注册一个监听器,接受一个字符串event和一个回调函数
server.on('connection',function(stream){
console.log('someone connected!');
})
3.once(event,listener) //未指定事件注册一个单次监听器,即 监听器最多只会触发一次,出发后立即解除该监听器
4.removeListener(event,listener) //移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器,它会接受两个参数,第一个是事件名称,第二个是回调函数名称
var callback = function(stream){
console.log('someone connected')
}
server.on('connection',callback);
server.removeListener('connection',callback);
5.removeAllListener([event]) //移除所有事件的所有监听,如果指定事件,则移除该事件的所有监听
6.setMaxListener(n) //默认10个 设置数字可以提高监听器的默认限制数量
7.listeners(event) //返回指定事件的监听数组
8.emit(event,[arg1],[arg2],...) //按监听器的书序执行每个监听器,如果事件有注册监听返回true,否者返回false
7-3 类方法
1.listenerCount(emitter,event) //返回指定事件的监听器数量
events.EventEmitter.listenerCount(emitter,eventName) //已废弃,不推荐
events.emitter.listenerCount(eventName) //推荐
7-4 事件
1.newListener //该事件在添加新监听器时被触发
2.removeListener //从指定监听器数组中删除一个监听器,需要注意的是,此操作将会改变处于被删监听器之后的那些监听器索引
7-5 实例
通过connection的连接事件来演示EventEmitter类的应用
创建main.js文件,代码如下:
var events = require('events');
var eventEmitter = new events.EventEmitter();
//监听器1
var listener1 = function listener1(){
console.log('监听器 listener1 执行。');
}
//监听器2
var listener2 = function listener2(){
console.log('监听器 listener2 执行。');
}
// 绑定 connection 事件,处理函数为 listener1
eventEmitter.addListener('connection',listener1);
// 绑定 connection 事件,处理函数为 listener2
eventEmitter.on('connection',listener2);
var eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + '个监听器监听连接事件')
//触发 connection事件
eventEmitter.emit('connection')
// 移除监绑定的 listener1 函数
eventEmitter.removeListener('connection',listener1);
console.log("listener1 不再受监听。");
//触发 connection事件
eventEmitter.emit('connection')
eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + '个监听器监听连接事件')
console.log("程序执行完毕。");
7-6 error事件
EventEmitter定义了一个特殊的事件error,它包含了错误的语义,我们在遇到异常的时候,通常会触发error事件
当error被触发时,EventEmitter规定如果没有响应的监听器,Node.js会把他当做异常,退出程序并输出错误信息。
我们一般要为会触发error事件的对象设置监听器,别面遇到错误后整个程序崩溃,例如:
//error.js
var events = require('events');
var emitter = new events.EventEmitter();
emitter.emit('error');
7-7 继承EventEmitter
大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。
为什么要这样做呢?原因有两点:
首先,具有某个实体功能的对象实现事件符合语义, 事件的监听和发生应该是一个对象的方法。
其次 JavaScript 的对象机制是基于原型的,支持 部分多重继承,继承 EventEmitter 不会打乱对象原有的继承关系。