Node.js 中的很多核心模块,都是基于事件来实现的。一些对象通过触发一些事件,使得相应的监听器函数能够被调用执行。所有能够触发事件的对象都是 EventEmitter
类的实例。这些对象可以通过 eventEmitter.on()
方法,将多个函数附加到由这个对象触发的对应命名事件中。当 EventEmitter
对象触发一个事件时,所有附着在那个事件上的函数都会被同步调用。
下面的例子展示了一个简单的 EventEmitter
实例,其中包含一个单独的监听器。eventEmitter.on()
方法用来注册监听器, eventEmitter.emit()
方法用来触发相应的事件。
一般不会直接使用 EventEmitter 作为构造实例的对象,而是会通过继承来自定义一个 EventEmitter,使用方式如下:
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('an event occurred!');
});
myEmitter.emit('event');
// 允许对同一事件添加多个监听器函数,
// 也允许通过事件来传递多个参数:
myEmitter.on('event', (a, b, c) => {
// Something
})
myEmitter.emit('event', 'a', 'b', 'c');
默认情况下,对于同一事件最多只能同时绑定 10 个监听器,但这个限制可以通过 emitter.setMaxListeners(n)
函数来修改,或者直接通过修改相应对象的 defaultMaxListeners
属性来修改其所有实例的此项默认值。
事件触发时,相应事件监听器通过监听器列表顺序依次进行同步调用。所以应当避免出现竞态条件和一些逻辑错误,若不可避免,应该选用 setImmediate()
或者 process.nextTick()
等函数将其变为异步方法来处理。
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
setImmediate(() => {
console.log('this happens asynchronously');
});
});
myEmitter.emit('event', 'a', 'b');
在 EventEmitter
实例中发生错误时,会触发 'error'
事件。如果没有任何监听器去监听 'error'
事件,当 'error'
事件触发时,就会将 error 抛出,随后将导致 node 进程退出。若想增加程序的稳定性,使得 node 不因为监听的 'error'
事件而导致崩溃,需要在 process
对象中监听 'uncaughtException
事件,这样就能阻止因此而导致的 node 进程退出了。
const myEmitter = new MyEmitter();
process.on('uncaughtException', (err) => {
console.log('whoops! there was an error');
});
myEmitter.emit('error', new Error('whoops!'));
// Prints: whoops! there was an error
newListener
事件:当新的监听器绑定后,会触发 'newListener'
事件,并将传递事件名称及监听器函数作为参数。newListener
事件:当监听器取消绑定后,会触发 'newListener'
事件eventNames(eventName)
:获取相应事件已经绑定的监听事件名称数组listenerCount(eventName)
:获取相应事件已经绑定的监听器数量addListener(eventName, listener)
: 同 on()
方法,绑定事件监听器并加入到监听器数组的末尾once(eventName, listener)
: 注册一个仅会被调用一次的监听器,一旦所监听的时间被触发,此监听器便会立即被移除,随后再进行调用。prependListener(eventName, listener)
: 绑定事件监听器,并将监听器函数插入监听器数组开头,使之能够被首先调用。prependOnceListener(eventName, listener)
: 与 prependListener()
类似,但只触发一次。removeListener(eventName, listener)
: 移除相应事件的一个监听器,与 addListener()
一样需要提供监听器函数作为参数。若在事件触发过程中调用,则不会在此次事件中生效,直至此次事件的所有监听器函数执行完毕。removeAllListeners([eventName])
: 可以移除此实例中已绑定的全部监听器,或者是移除指定事件中所有的监听器。