Node.js 模块之 Event

后端2016-10-220 篇评论 Node.js

Node.js 中的很多核心模块,都是基于事件来实现的。一些对象通过触发一些事件,使得相应的监听器函数能够被调用执行。所有能够触发事件的对象都是 EventEmitter 类的实例。这些对象可以通过 eventEmitter.on() 方法,将多个函数附加到由这个对象触发的对应命名事件中。当 EventEmitter 对象触发一个事件时,所有附着在那个事件上的函数都会被同步调用。

使用 Events 模块

下面的例子展示了一个简单的 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 属性来修改其所有实例的此项默认值。

异步 VS 同步

事件触发时,相应事件监听器通过监听器列表顺序依次进行同步调用。所以应当避免出现竞态条件和一些逻辑错误,若不可避免,应该选用 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

EventEmitter 内置事件

  • newListener 事件:当新的监听器绑定后,会触发 'newListener' 事件,并将传递事件名称及监听器函数作为参数。
  • newListener 事件:当监听器取消绑定后,会触发 'newListener' 事件

EventEmitter 实例的其它方法

  • eventNames(eventName):获取相应事件已经绑定的监听事件名称数组
  • listenerCount(eventName):获取相应事件已经绑定的监听器数量
  • addListener(eventName, listener): 同 on() 方法,绑定事件监听器并加入到监听器数组的末尾
  • once(eventName, listener): 注册一个仅会被调用一次的监听器,一旦所监听的时间被触发,此监听器便会立即被移除,随后再进行调用。
  • prependListener(eventName, listener): 绑定事件监听器,并将监听器函数插入监听器数组开头,使之能够被首先调用。
  • prependOnceListener(eventName, listener): 与 prependListener() 类似,但只触发一次。
  • removeListener(eventName, listener): 移除相应事件的一个监听器,与 addListener() 一样需要提供监听器函数作为参数。若在事件触发过程中调用,则不会在此次事件中生效,直至此次事件的所有监听器函数执行完毕。
  • removeAllListeners([eventName]): 可以移除此实例中已绑定的全部监听器,或者是移除指定事件中所有的监听器。

评论区

发表评论
用户名
(必填)
电子邮箱
(必填)
个人网站
(选填)
评论内容
Copyright © 2017 dremy.cn
皖ICP备16015002号