node.js之 EventEmitter
node的事件模块只包含了一个类:EventEmitter。这个类在node的内置模块和第三方模块中大量使用。EventEmitter本质上是一个观察者模式的实现。
所谓观察者模式:
它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。
因此最基本的EventEmitter功能,包含了一个观察者和一个被监听的对象,对应的实现就是EventEmitter中的on和emit:
var events=require('events');
var eventEmitter=new events.EventEmitter();
eventEmitter.on('say',function(name){
console.log('Hello',name);
})
eventEmitter.emit('say','Jony yu');
eventEmitter是EventEmitter模块的一个实例,通过eventEmitter的on方法监听,eventEmitter的emit方法say事件,发出say事件,从而执行相应的函数。
EventEmitter模块的基本用法
.addListener()或.on()为指定事件添加一个监听器到监听器数组尾部(这俩作用一样,on是addListener的简写形式)
prependListener(event,listener) 添加一个监听器到监听器数组头部
once(event, listener) 添加一个单次监听器到监听器数组尾部, 监听器最多只会触发一次,触发后立刻解除该监听器。
removeListener 或 off 移除指定事件的某个监听器
removeAllListeners([event]) 移除所有事件的所有监听器, 如果指定事件,则移除指定事件的所有监听器。
setMaxListeners(n) 默认情况下, EventEmitters 如果你添加的监听器超过 10 个就会输出警告信息。 setMaxListeners 函数用于提高监听器的默认限制的数量。
listeners(event) 返回指定事件的监听器数组。
emit(event, [arg1], [arg2], [...]) 按参数的顺序执行每个监听器,如果事件有注册监听返回 true,否则返回 false。
例子:
添加监听事件
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.once('someEvent', function(arg1, arg2) {
console.log('listener3', arg1, arg2); //只执行一次
});
emitter.prependListener('someEvent', function(arg1, arg2) {
console.log('listener4', arg1, arg2); //监听数组头部
});
emitter.emit('someEvent', 'arg1 参数', 'arg2 参数');
emitter.emit('someEvent', 'arg1 参数', 'arg2 参数');
移除事件
//event.js 文件
var events = require('events');
var eventEmitter = new events.EventEmitter();
// 监听器 #1
var listener1 = function listener1() {
console.log('监听器 listener1 执行。');
}
// 绑定 connection 事件,处理函数为 listener1
eventEmitter.addListener('connection', listener1);
// 处理 connection 事件
eventEmitter.emit('connection');
// 移除监绑定的 listener1 函数
eventEmitter.removeListener('connection', listener1);
console.log("listener1 不再受监听。");
// 触发连接事件
eventEmitter.emit('connection');
console.log("程序执行完毕。");
移除所有监听事件:
// 监听器 #1
var listener1 = function listener1() {
console.log('监听器 listener1 执行。');
}
var listener2 = function listener2() {
console.log('监听器 listener2 执行。');
}
eventEmitter.addListener('connection', listener1);
eventEmitter.on('connection2', listener2);
console.log(eventEmitter.listeners('connection') )
eventEmitter.removeAllListeners('connection')
eventEmitter.emit('connection');
eventEmitter.emit('connection2');
eventEmitter.removeAllListeners()
eventEmitter.emit('connection2');
console.log("程序执行完毕。");
设置监听器最大个数:
//event.js 文件
var events = require('events');
var eventEmitter = new events.EventEmitter();
// 监听器 #1
var listener1 = function listener1() {
console.log('监听器 listener1 执行。');
}
var listener2 = function listener2() {
console.log('监听器 listener2 执行。');
}
eventEmitter.setMaxListeners(3)
eventEmitter.addListener('connection', listener1);
eventEmitter.addListener('connection', listener1);
eventEmitter.addListener('connection', listener1);
eventEmitter.addListener('connection', listener2);
eventEmitter.addListener('connection', listener1);
eventEmitter.addListener('connection', listener1);
eventEmitter.addListener('connection', listener1);
eventEmitter.addListener('connection', listener2);
eventEmitter.emit('connection');
console.log("程序执行完毕。");
error 事件
EventEmitter 定义了一个特殊的事件 error,它包含了错误的语义,我们在遇到 异常的时候通常会触发 error 事件。
当 error 被触发时,EventEmitter 规定如果没有响 应的监听器,Node.js 会把它当作异常,退出程序并输出错误信息。
我们一般要为会触发 error 事件的对象设置监听器,避免遇到错误后整个程序崩溃。例如:
var events = require('events');
var emitter = new events.EventEmitter();
emitter.emit('error');
运行时会显示以下错误:
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: Uncaught, unspecified 'error' event.
at EventEmitter.emit (events.js:50:15)
at Object.<anonymous> (/home/byvoid/error.js:5:9)
at Module._compile (module.js:441:26)
at Object..js (module.js:459:10)
at Module.load (module.js:348:31)
at Function._load (module.js:308:12)
at Array.0 (module.js:479:10)
at EventEmitter._tickCallback (node.js:192:40)
继承 EventEmitter
大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。
为什么要这样做呢?原因有两点:
首先,具有某个实体功能的对象实现事件符合语义, 事件的监听和发射应该是一个对象的方法。
其次 JavaScript 的对象机制是基于原型的,支持 部分多重继承,继承 EventEmitter 不会打乱对象原有的继承关系。