node.js 事件和 EventEmitter 类
在学习stream的时候,看到文档中有这么一句:所有的 Stream 对象都是 EventEmitter 的实例,常用的事件有 data,end 等等。
当时就在想为什么要说是 EventEmitter 的实例这句话呢?还有事件是什么?继续看下去就明白了。
EventEmitter 类
events 模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。
上面这句话就可以看出来在node.js中所有的事件操作都封装在 EventEmitter 中,那么具体是怎么添加事件和触发事件呢?
下面看一个实例:
const eventEmitter = require('events').EventEmitter;
// 创建EventEmitter实例
let event = new EventEmitter();
// 注册a_event事件,第二个参数是一个函数,在这里叫做监听器
event.on('a_event', () => {
console.log('触发 a_event 事件');
});
setTimeout(() => {
// 一秒后触发a_event事件
event.emit('a_event');
}, 1000)
out:
触发 a_event 事件
上面这段代码的原理是 event 对象注册了事件 a_event 的一个监听器,然后我们通过 setTimeout 在 1000 毫秒以后向 event 对象发送事件 a_event,此时会调用 a_event 的监听器。
原来可以通过EventEmitter类自定义一个事件并且手动触发它。
EventEmitter 的简单用法
EventEmitter 的每个事件由一个事件名和若干个参数组成,事件名是一个字符串,通常表达一定的语义。
对于每个事件,EventEmitter 支持 若干个事件监听器。当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。
let events = require('events');
// 创建EventEmitter实例
let emitter = new events.EventEmitter();
// 注册第一个事件监听器
emitter.on('a_event', (arg1, arg2) => {
console.log('listener1', arg1, arg2);
});
// 注册第二个事件监听器
emitter.on('a_event', (arg1, arg2) => {
console.log('listener2', arg1, arg2);
});
// 触发事件
emitter.emit('a_event', 'arg1 参数', 'arg2 参数');
out:
listener1 arg1 参数 arg2 参数
listener2 arg1 参数 arg2 参数
EventEmitter 的常用方法
-
on(event, listener)
// 为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数。 server.on('connection', function (stream) { console.log('someone connected!'); });
-
once(event, listener)
// 为指定事件注册一个单次监听器,即 监听器最多只会触发一次,触发后立刻解除该监听器。 server.once('connection', function (stream) { console.log('Ah, we have our first user!'); });
-
emit(event, [arg1], [arg2], […])
// 按监听器的顺序执行执行每个监听器,如果事件有注册监听返回 true,否则返回 false。 emitter.emit('a_event', 'arg1 参数', 'arg2 参数');
-
listeners(event)
// 返回指定事件的监听器数组。 emitter.listeners('a_event') // 返回指定事件的监听器数量。 emitter.listeners('a_event').length
-
addListener(event, listener)
// 为指定事件添加一个监听器到监听器数组的尾部。
-
removeListener(event, listener)
// 移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器。 // 它接受两个参数,第一个是事件名称,第二个是回调函数名称。 var callback = function(stream) { console.log('someone connected!'); }; server.on('connection', callback); // ... server.removeListener('connection', callback);
-
removeAllListeners([event])
// 移除所有事件的所有监听器, 如果指定事件,则移除指定事件的所有监听器。
-
setMaxListeners(n)
// 默认情况下, EventEmitters 如果你添加的监听器超过 10 个就会输出警告信息。 setMaxListeners 函数用于提高监听器的默认限制的数量。
EventEmitter 的事件
-
newListener
// 该事件在添加新监听器时被触发。
-
newListener
// 从指定监听器数组中删除一个监听器。需要注意的是,此操作将会改变处于被删监听器之后的那些监听器的索引。
EventEmitter 的 error 事件
EventEmitter 定义了一个特殊的事件 error,它包含了错误的语义,我们在遇到 异常的时候通常会触发 error 事件。
当 error 被触发时,EventEmitter 规定如果没有响 应的监听器,Node.js 会把它当作异常,退出程序并输出错误信息。
我们一般要为会触发 error 事件的对象设置监听器,避免遇到错误后整个程序崩溃。
看两个例子:
-
不为 error 事件设置监听器
// 创建EventEmitter实例 let emitter = new events.EventEmitter(); // 直接触发 error 事件 emitter.emit('error'); // 程序会在上面终止,不会打印 end console.log('end'); out: throw err; // Unhandled 'error' event ...
-
为 error 事件设置监听器
// 创建EventEmitter实例 let emitter = new events.EventEmitter(); // 为 error 设置监听器 emitter.on('error', () => { console.error('事件异常'); }); // 直接触发 error 事件 emitter.emit('error'); // 程序不会在上面终止,会打印 end console.log('end'); out: 事件异常 end
继承 EventEmitter
大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。
到这来终于明白了为什么说所有的 Stream 对象都是 EventEmitter 的实例,因为 stream 对象继承了EventEmitter类,这样它就可以使用EventEmitter类的事件功能(EventEmitter类方法、属性、事件等),而不需要自己再去定义这些功能。