文章已同步至掘金:https://juejin.cn/post/6844903921652072461
欢迎访问😃,有任何问题都可留言评论哦~
Node中的大多数核心API类型的对象(又称触发器,Emitter)会触发命名事件来调用函数(又称监听器,Listener)
例如,net.Server
会在每次有新连接时触发事件,fs.ReadStream
会在打开文件时触发事件,stream
会在数据可读时触发事件。
所有能触发事件的对象都是 EventEmitter
类的实例。 这些对象有一个 eventEmitter.on()
函数,用于将一个或多个函数绑定到命名事件上。
当 EventEmitter
对象触发一个事件时,所有绑定在该事件上的函数都会被同步地调用。 被调用的监听器返回的任何值都将会被忽略并丢弃。
例子:
一个简单的 EventEmitter
实例,绑定了一个监听器。 eventEmitter.on()
用于注册监听器, eventEmitter.emit()
用于触发事件。
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('触发事件');
});
myEmitter.emit('event');
将参数和 this
传给监听器
eventEmitter.emit()
方法可以传任意数量的参数到监听器函数。 当监听器函数被调用时, this
关键词会被指向监听器所绑定的 EventEmitter
实例。
const myEmitter = new MyEmitter();
myEmitter.on('event', function(a, b) {
console.log(a, b, this, this === myEmitter);
// 打印:
// a b MyEmitter {
// domain: null,
// _events: { event: [Function] },
// _eventsCount: 1,
// _maxListeners: undefined } true
});
myEmitter.emit('event', 'a', 'b');
也可以使用 箭头函数 作为监听器,但 this
关键词不会指向 EventEmitter
实例:
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
console.log(a, b, this);
// 打印: a b {}
});
myEmitter.emit('event', 'a', 'b');
异步 与 同步
EventEmitter
会按照监听器注册的顺序同步地调用所有监听器。 所以必须确保事件的排序正确,且避免竞态条件。
可以使用 setImmediate()
或 process.nextTick()
切换到异步模式:
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
setImmediate(() => {
console.log('异步进行');
});
});
myEmitter.emit('event', 'a', 'b');
仅处理事件一次
当使用 eventEmitter.on()
注册监听器时,监听器会在每次触发命名事件时被调用。
const myEmitter = new MyEmitter();
let m = 0;
myEmitter.on('event', () => {
console.log(++m);
});
myEmitter.emit('event');
// 打印: 1
myEmitter.emit('event');
// 打印: 2
使用 eventEmitter.once()
可以注册最多可调用一次的监听器。 当事件被触发时,监听器会被注销,然后再调用。
const myEmitter = new MyEmitter();
let m = 0;
myEmitter.once('event', () => {
console.log(++m);
});
myEmitter.emit('event');
// 打印: 1
myEmitter.emit('event');
// 不触发
错误事件
当 EventEmitter
实例出错时,应该触发 'error'
事件。 这些在 Node 中被视为特殊情况。
如果没有为 'error'
事件注册监听器,则当 'error'
事件触发时,会抛出错误、打印堆栈跟踪、并退出 Node.js 进程。
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('错误信息'));
// 抛出错误并使 Node.js 崩溃。
作为最佳,应该始终为 'error'
事件注册监听器。
const myEmitter = new MyEmitter();
myEmitter.on('error', (err) => {
console.error('错误信息');
});
myEmitter.emit('error', new Error('错误'));
// 打印: 错误信息
EventEmitter
类
EventEmitter
类由 events
模块定义:
const EventEmitter = require('events');
newListener
- event - 字符串,事件名称
- listener - 处理事件函数
该事件在添加新监听器时被触发。
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
- event - 字符串,事件名称
- listener - 处理事件函数
从指定监听器数组中删除一个监听器。需要注意的是,此操作将会改变处于被删监听器之后的那些监听器的索引。
myEmitter.on('event', () => {});
myEmitter.on('event', () => {});
console.log(EventEmitter.listenerCount(myEmitter, 'event'));
// Prints: 2
addListener(event, listener)
为指定事件添加一个监听器到监听器数组的尾部。
on(event, listener)
为指定事件注册一个监听器,接受一个字符串 event
和一个回调函数。
server.on('connection', function (stream) {
console.log('someone connected!');
});
emit(event, [arg1], [arg2], […])
按监听器的顺序执行执行每个监听器,如果事件有注册监听返回 true,否则返回 false。
once(event, listener)
为指定事件注册一个单次监听器,即 监听器最多只会触发一次,触发后立刻解除该监听器。
server.once('connection', function (stream) {
console.log('Ah, we have our first user!');
});
off(event, listener)
emitter.removeListener()
的别名。
removeListener(event, listener)
移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器。
它接受两个参数,第一个是事件名称,第二个是回调函数名称。
let callback = function(stream) {
console.log('someone connected!');
};
server.on('connection', callback);
// ...
server.removeListener('connection', callback);
removeAllListeners([event])
移除所有事件的所有监听器, 如果指定事件,则移除指定事件的所有监听器。
setMaxListeners(n)
默认情况下, EventEmitters
如果你添加的监听器超过 10 个就会输出警告信息。 setMaxListeners
函数用于提高监听器的默认限制的数量。
设置 EventEmitter.defaultMaxListeners
要谨慎,因为会影响所有 EventEmitter
实例,包括之前创建的。 因而,优先使用 emitter.setMaxListeners(n)
而不是 EventEmitter.defaultMaxListeners
。
emitter.setMaxListeners(emitter.getMaxListeners() + 1);
defaultMaxListeners
默认情况下,每个事件可以注册最多 10 个监听器。 可以使用 emitter.setMaxListeners(n)
方法改变单个 EventEmitter
实例的限制。 可以使用 EventEmitter.defaultMaxListeners
属性改变所有 EventEmitter
实例的默认值。 如果此值不是一个正数,则抛出 TypeError
。
设置 EventEmitter.defaultMaxListeners
要谨慎,因为会影响所有 EventEmitter
实例,包括之前创建的。 因而,优先使用 emitter.setMaxListeners(n)
而不是 EventEmitter.defaultMaxListeners
。
emitter.setMaxListeners(emitter.getMaxListeners() + 1);
emitter.once('event', () => {
// 做些操作
emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0));
});
getMaxListeners()
返回 EventEmitter
当前的监听器最大限制数的值,该值可以使用 emitter.setMaxListeners(n)
设置或默认为 EventEmitter.defaultMaxListeners
。
listeners(event)
返回指定事件的监听器数组。
返回名为 event
的事件的监听器数组的副本。
server.on('connection', (stream) => {
console.log('有连接');
});
console.log(util.inspect(server.listeners('connection')));
// 打印: [ [Function] ]
listenerCount(emitter, event)
返回指定事件的监听器数量。
events.EventEmitter.listenerCount(emitter, eventName) //已废弃,不推荐
events.emitter.listenerCount(eventName) //推荐
eventNames()
返回一个数组
返回已注册监听器的事件名数组。 数组中的值为字符串或 Symbol
。
const EventEmitter = require('events');
const myEE = new EventEmitter();
myEE.on('foo', () => {});
myEE.on('bar', () => {});
const sym = Symbol('symbol');
myEE.on(sym, () => {});
console.log(myEE.eventNames());
// 打印: [ 'foo', 'bar', Symbol(symbol) ]
rawListeners(event)
返回 event
事件的监听器数组的拷贝,包括封装的监听器(例如由 .once() 创建的)。
const emitter = new EventEmitter();
emitter.once('log', () => console.log('只记录一次'));
// 返回一个数组,包含了一个封装了 `listener` 方法的监听器。
const listeners = emitter.rawListeners('log');
const logFnWrapper = listeners[0];
// 打印 “只记录一次”,但不会解绑 `once` 事件。
logFnWrapper.listener();
// 打印 “只记录一次”,且移除监听器。
logFnWrapper();
emitter.on('log', () => console.log('持续地记录'));
// 返回一个数组,只包含 `.on()` 绑定的监听器。
const newListeners = emitter.rawListeners('log');
// 打印两次 “持续地记录”。
newListeners[0]();
emitter.emit('log');
评论区