Node.js EventEmitter 学习

说起Node中几个最重要的模块,那么events模块一定在其中,在Node中很多很多的其他模块都是基于或者依赖于events模块。

那么我们来了解一下什么是events模块和events模块的使用,和一些注意点

我们参看的Node v6.10.3文档, 对于EventEmitter的方法我们不解释,相对比较简单,官方也给出了较多的例子,完全可以参看官方的文档,这里就说明一些注意点

EventEmitter实例化

首先很多的教程里面会写以下的代码来实例化一个EventEmitter

1
2
var events = require('events');
var emitter = new events.EventEmitter();

但是官方给出的例子却是

1
2
3
4
5
const EventEmitter = require('events');

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();

REPL中输出const EventEmitter = require('events');中的EventEmitter

1
2
3
4
5
6
7
EventEmitter
{ [Function: EventEmitter]
EventEmitter: [Circular], // 循环引用
usingDomains: true,
defaultMaxListeners: [Getter/Setter],
init: [Function],
listenerCount: [Function] }

同时在翻看源码之后看到

1
2
3
4
module.exports = EventEmitter;

// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;

所以,两种方式都是可以的,但是感觉按照官方的方式会更好。

error事件

当 EventEmitter 实例中发生错误时,会触发一个 ‘error’ 事件。 这在 Node.js 中是特殊情况。

如果 EventEmitter 没有为 ‘error’ 事件注册至少一个监听器,则当 ‘error’ 事件触发时,会抛出错误、打印堆栈跟踪、且退出 Node.js 进程。

1
2
3
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('whoops!'));
// 抛出错误,并使 Node.js 奔溃

所以应该始终为 ‘error’ 事件注册监听器。

1
2
3
myEmitter.on('error', (err) => {
console.error('有错误');
});

另外提一句为了防止 Node.js 进程崩溃,可以在 process 对象的 uncaughtException 事件上注册监听器。

1
2
3
4
5
6
7
const myEmitter = new MyEmitter();

process.on('uncaughtException', (err) => {
console.error('有错误');
});

myEmitter.emit('error', new Error('whoops!'));

this作用域

在ES6加入后,有了箭头函数,有时候会导致监听器的this作用域的不同,这里需要稍微注意一下

1
2
3
4
5
6
7
8
9
10
11
const myEmitter = new MyEmitter();
myEmitter.on('event', function(a, b) {
console.log(a, b, this);
// 打印:
// a b MyEmitter {
// domain: null,
// _events: { event: [Function] },
// _eventsCount: 1,
// _maxListeners: undefined }
});
myEmitter.emit('event', 'a', 'b');

箭头函数版本

1
2
3
4
5
6
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
console.log(a, b, this);
// 打印: a b {}
});
myEmitter.emit('event', 'a', 'b');

相信了解过箭头函数的原理的都应该可以理解。

on()addListener() 的区别

没有区别

1
EventEmitter.prototype.on = EventEmitter.prototype.addListener;