Node.js API详解之 events

大多数 Node.js 核心 API 都采用惯用的异步事件驱动架构,其中某些类型的对象(触发器)会周期性地触发命名事件来调用函数对象(监听器)
例如,net.Server 对象会在每次有新连接时触发事件;fs.ReadStream 会在文件被打开时触发事件;流对象 会在数据可读时触发事件。
所有能触发事件的对象都是 EventEmitter 类的实例。 这些对象开放了一个 eventEmitter.on() 函数,允许将一个或多个函数绑定到会被对象触发的命名事件上。
事件名称通常是驼峰式的字符串,但也可以使用任何有效的 JavaScript 属性名。
当 EventEmitter 对象触发一个事件时,所有绑定在该事件上的函数都被同步地调用。 监听器的返回值会被丢弃。

目录:

EventEmitter 类

说明:

EventEmitter 类由 events 模块定义和开放的,使用以下方式引用:

const EventEmitter = require('events');

当新的监听器被添加时,所有的 EventEmitter 会触发 ‘newListener’ 事件;
当移除已存在的监听器时,则触发 ‘removeListener’。

newListener 事件

说明:

EventEmitter 实例会在一个监听器被添加到其内部监听器数组之前触发自身的 ‘newListener’ 事件。
事实上,在添加监听器之前触发事件有一个微妙但重要的副作用:
在’newListener’ 回调函数中, 一个监听器的名字如果和已有监听器名称相同,
则在被插入到EventEmitter实例的内部监听器数组时, 该监听器会被添加到其它同名监听器的前面。
注册了 ‘newListener’ 事件的监听器会传入事件名与被添加的监听器的引用。
eventName: 要监听的事件的名称
listener: 事件的句柄函数

demo:

const MyEmitter = require('events');

const myEmitter = new MyEmitter();
// 只处理一次,所以不会无限循环
myEmitter.once('newListener', (event, listener) => {
  if (event === 'event') {
    // 在开头插入一个新的监听器
    myEmitter.on('event', () => {
      console.log('B');
    });
  }
});
myEmitter.on('event', () => {
  console.log('A');
});
myEmitter.emit('event');
// 打印:
//   B
//   A

removeListener 事件

说明:

‘removeListener’ 事件在 listener 被移除后触发。
注册了 ‘removeListener’ 事件的监听器会传入事件名与被添加的监听器的引用。
eventName: 要监听的事件的名称
listener: 事件的句柄函数

demo:

const MyEmitter = require('events');

const myEmitter = new MyEmitter();

myEmitter.once('removeListener', (event, listener) => {
  	console.log('%s事件被移除', event);
});
const callback = (stream) => {
	console.log('A');
}
myEmitter.on('event', callback);
myEmitter.removeListener('event', callback);
// event事件被移除

error 事件

说明:

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

demo:

const MyEmitter = require('events');

const myEmitter = new MyEmitter();

const callback = (error) => {
	console.log('发生异常:', error);
}
myEmitter.on('error', callback);
myEmitter.emit('error', new Error('出错了!'));
// 发生异常: Error: 出错了!
//     at Object. (/Users/xiaoqiang/Documents/work/demo/NodeApi/app.js:12:25)
//     at Module._compile (module.js:660:30)
//     ...

EventEmitter.defaultMaxListeners

说明:

每个事件默认可以注册最多 10 个监听器。
单个 EventEmitter 实例的限制可以使用 emitter.setMaxListeners(n) 方法改变。
所有 EventEmitter 实例的默认值可以使用 EventEmitter.defaultMaxListeners 属性改变。
如果这个值不是正数, 那将抛出 TypeError错误.
设置 EventEmitter.defaultMaxListeners 要谨慎,因为会影响所有 EventEmitter 实例,包括之前创建的。
注意,调用 emitter.setMaxListeners(n) 优先于 EventEmitter.defaultMaxListeners。
注意,这不是一个硬性限制。 EventEmitter 实例允许添加更多的监听器,但会向 stderr 输出跟踪警告,
表明检测到一个可能的 EventEmitter 内存泄漏。
对于任何单个 EventEmitter 实例,emitter.getMaxListeners() 和 emitter.setMaxListeners() 方法可用于暂时地消除此警告。
–trace-warnings 命令行标志可用于显示此类警告的堆栈跟踪。
触发的警告可以使用 process.on(‘warning’) 检查,还有额外的 emitter、type 和 count 属性,
分别代表事件触发器实例的引用、事件的名称、和附加的监听器的数量。其 name 属性设置为 MaxListenersExceededWarning。

demo:

const MyEmitter = require('events');

const myEmitter = new MyEmitter();

console.log('最多可注册%d个监听器', MyEmitter.defaultMaxListeners);
// 最多可注册10个监听器

MyEmitter.defaultMaxListeners = 20;

console.log('最多可注册%d个监听器', MyEmitter.defaultMaxListeners);
// 最多可注册20个监听器

emitter.getMaxListeners()

说明:

返回 EventEmitter 当前的最大监听器限制值,该值可以通过 emitter.setMaxListeners(n) 设置或默认为

demo:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

console.log(myEmitter.getMaxListeners());
// 10

emitter.setMaxListeners(n)

说明:

默认情况下,如果为特定事件添加了超过 10 个监听器,则 EventEmitter 会打印一个警告。
此限制有助于寻找内存泄露。 但是,并不是所有的事件都要被限为 10 个。
emitter.setMaxListeners() 方法允许修改指定的 EventEmitter 实例的限制。
值设为 Infinity(或 0)表明不限制监听器的数量。
返回一个 EventEmitter 引用,可以链式调用。

demo:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();
myEmitter.setMaxListeners(20);

console.log(myEmitter.getMaxListeners());
// 20

EventEmitter.listenerCount(emitter, eventName)(已废弃)

说明:

该方法返回一个EventEmitter实例上绑定的指定名字的事件监听器。

demo:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

const callback = (error) => {
	console.log('发生异常:', error);
}
myEmitter.on('error', callback);
myEmitter.on('error', callback);
myEmitter.on('error', callback);

console.log(EventEmitter.listenerCount(myEmitter, 'error'));
// 3

emitter.listenerCount(eventName)

说明:

返回正在监听名为 eventName 的事件的监听器的数量。

demo:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

const callback = (error) => {
	console.log('发生异常:', error);
}
myEmitter.on('error', callback);
myEmitter.on('error', callback);
myEmitter.on('error', callback);

console.log(myEmitter.listenerCount('error'));
// 3

emitter.on(eventName, listener)

说明:

添加 listener 函数到名为 eventName 的事件的监听器数组的末尾。
不会检查 listener 是否已被添加。
多次调用并传入相同的 eventName 和 listener 会导致 listener 被添加与调用多次。
默认情况下,事件监听器会按照添加的顺序依次调用。
emitter.prependListener() 方法可用于将事件监听器添加到监听器数组的开头。

demo:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

const callback = () => {
	console.log('自定义事件');
}
myEmitter.on('event', callback);

myEmitter.emit('event');
// 自定义事件

emitter.once(eventName, listener)

说明:

添加一个单次 listener 函数到名为 eventName 的事件。
下次触发 eventName 事件时,监听器会被移除,然后调用。
默认情况下,事件监听器会按照添加的顺序依次调用。
emitter.prependOnceListener() 方法可用于将事件监听器添加到监听器数组的开头。

demo:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

const callback = () => {
	console.log('自定义事件');
}
myEmitter.once('event', callback);

myEmitter.emit('event');

myEmitter.emit('event');
// 自定义事件

emitter.addListener(eventName, listener)

说明:

emitter.on(eventName, listener) 的别名。

demo:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

const callback = () => {
	console.log('自定义事件');
}
myEmitter.addListener('event', callback);

myEmitter.emit('event');
// 自定义事件

emitter.prependListener(eventName, listener)

说明:

添加 listener 函数到名为 eventName 的事件的监听器数组的开头。
不会检查 listener 是否已被添加。
多次调用并传入相同的 eventName 和 listener 会导致 listener 被添加与调用多次。

demo:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

const callback = () => {
	console.log('自定义事件');
}
myEmitter.addListener('event', callback);

myEmitter.prependListener('event', () => console.log('b'));

myEmitter.emit('event');
// b
// 自定义事件

emitter.prependOnceListener(eventName, listener)

说明:

添加一个单次 listener 函数到名为 eventName 的事件的监听器数组的开头。
下次触发 eventName 事件时,监听器会被移除,然后调用。

demo:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

const callback = () => {
	console.log('自定义事件');
}
myEmitter.once('event', callback);

myEmitter.prependOnceListener('event', () => console.log('b'));

myEmitter.emit('event');
// b
// 自定义事件

emitter.listeners(eventName)

说明:

返回名为 eventName 的事件的监听器数组的副本。

demo:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

const callback = () => {
	console.log('自定义事件');
}
myEmitter.on('event', callback);
myEmitter.on('event', callback);

console.log( myEmitter.listeners('event').toString() );
// () => {
// 	console.log('自定义事件');
// },() => {
// 	console.log('自定义事件');
// }

emitter.emit(eventName[, …args])

说明:

按监听器的注册顺序,同步地调用每个注册到名为 eventName 事件的监听器,并传入提供的参数。
如果事件有监听器,则返回 true ,否则返回 false。

demo:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

const callback = () => {
	console.log('自定义事件');
}
myEmitter.on('event', callback);

myEmitter.emit('event');
// 自定义事件

emitter.eventNames()

说明:

返回一个列出触发器已注册监听器的事件的数组。 数组中的值为字符串或符号。

demo:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

const callback = () => {
	console.log('自定义事件');
}
myEmitter.on('event', callback);
myEmitter.on('click', callback);
myEmitter.on('close', callback);

console.log( myEmitter.eventNames() );
// [ 'event', 'click', 'close' ]

emitter.removeListener(eventName, listener)

说明:

从名为 eventName 的事件的监听器数组中移除指定的 listener。
removeListener 最多只会从监听器数组里移除一个监听器实例。
如果任何单一的监听器被多次添加到指定 eventName 的监听器数组中,则必须多次调用 removeListener 才能移除每个实例。
注意,一旦一个事件被触发,所有绑定到它的监听器都会按顺序依次触发。
这意味着,在事件触发后、最后一个监听器完成执行前,
任何 removeListener() 或 removeAllListeners() 调用都不会从 emit() 中移除它们。

demo:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

const callbackA = () => {
	console.log('自定义事件A');
}

const callbackB = () => {
	console.log('自定义事件B');
}
myEmitter.on('event', callbackA);
myEmitter.on('click', callbackB);

console.log( myEmitter.eventNames() );
// [ 'event', 'click' ]

myEmitter.removeListener('click', callbackB);

console.log( myEmitter.eventNames() );
// [ 'event' ]

emitter.removeAllListeners([eventName])

说明:

移除全部或指定 eventName 的监听器。
注意,在代码中移除其他地方添加的监听器是一个不好的做法,尤其是当 EventEmitter 实例是其他组件或模块(如 socket 或文件流)创建的。
返回一个 EventEmitter 引用,可以链式调用。

demo:

const EventEmitter = require('events');

const myEmitter = new EventEmitter();

const callbackA = () => {
	console.log('自定义事件A');
}

const callbackB = () => {
	console.log('自定义事件B');
}
myEmitter.on('event', callbackA);
myEmitter.on('event', callbackB);

console.log( myEmitter.eventNames() );
// [ 'event' ]

myEmitter.removeAllListeners('event', callbackA);

console.log( myEmitter.eventNames() );
// []