Open linfeimy opened 5 years ago
const EventEmitter = require('events');
console.log(EventEmitter);
{ [Function: EventEmitter] once: [Function: once],
EventEmitter: [Circular],
usingDomains: false,
defaultMaxListeners: [Getter / Setter],
init: [Function],
listenerCount: [Function]
}
const EventEmitter = require('events');
// console.log(EventEmitter);
class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('触发事件');
});
setTimeout(() => {
myEmitter.emit('event');
}, 3000);
将参数和 this 传给监听器 eventEmitter.emit() 方法可以传任意数量的参数到监听器函数。 当监听器函数被调用时, this 关键词会被指向监听器所绑定的 EventEmitter 实例。
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();
myEmitter.on('event', function (a, b) {
console.log(a + '\n', b + '\n', this );
console.log(this === myEmitter);
});
myEmitter.emit('event');
// undefined
// undefined
/*
MyEmitter {
_events: [Object: null prototype] {
event: [Function]
},
_eventsCount: 1,
_maxListeners: undefined
}
*/
// true
改为myEmitter.emit('event', 'a', 'b');
// a
// b
/*
MyEmitter {
_events: [Object: null prototype] {
event: [Function]
},
_eventsCount: 1,
_maxListeners: undefined
}
*/
// true
也可以使用 ES6 的箭头函数作为监听器。但 this 关键词不会指向 EventEmitter 实例:
myEmitter.on('event', (a, b) => {
console.log(a + '\n', b + '\n', this );
console.log(this === myEmitter);
});
myEmitter.emit('event', 'a', 'b');
// a
// b
// {}
// false
异步 VS 同步
EventEmitter
会按照监听器注册的顺序同步地调用所有监听器。 所以必须确保事件的排序正确,且避免竞态条件。 可以使用 setImmediate()
或process.nextTick()
切换到异步模式:
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
console.log(1);
setImmediate(() => {
console.log('异步进行');
});
console.log(2);
});
myEmitter.emit('event', 'a', 'b');
// 1
// 2
// 异步进行
仅处理事件一次
当使用 eventEmitter.on()
注册监听器时,监听器会在每次触发命名事件时被调用。
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();
let m = 0;
myEmitter.on('event', () => {
console.log(++m);
});
myEmitter.emit('event'); // 1
myEmitter.emit('event'); // 2
使用eventEmitter.once()
可以注册最多可调用一次的监听器。 当事件被触发时,监听器会被注销,然后再调用。
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();
let m = 0;
myEmitter.once('event', () => {
console.log(++m);
});
myEmitter.emit('event'); // 1
myEmitter.emit('event');
错误事件 当 EventEmitter 实例出错时,应该触发 'error' 事件。 这些在 Node.js 中被视为特殊情况。
如果没有为 'error' 事件注册监听器,则当 'error' 事件触发时,会抛出错误、打印堆栈跟踪、并退出 Node.js 进程。
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();
myEmitter.emit('error', new Error('错误消息'));
// throw er; // Unhandled 'error' event
// Error: 错误消息
为了防止崩溃 Node.js 进程,可以使用 domain 模块。 (但请注意,不推荐使用 domain 模块。)
作为最佳实践,应该始终为 'error' 事件注册监听器。
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {};
const myEmitter = new MyEmitter();
myEmitter.on('error', (err) => {
console.error('错误消息');
})
myEmitter.emit('error', new Error('错误消息'));
// 错误消息
events.once(emitter, name) 创建一个 Promise,当 EventEmitter 触发给定的事件时则会被解决,当 EventEmitter 触发 'error' 时则会被拒绝。 解决 Promise 时将会带上触发到给定事件的所有参数的数组。
const { once, EventEmitter } = require('events');
async function run() {
const ee = new EventEmitter();
process.nextTick(() => {
ee.emit('myEvent', 42);
});
const [value] = await once(ee, 'myEvent');
console.log(value);
const err = new Error('kaboom');
process.nextTick(() => {
ee.emit('error', err);
});
try {
await once(ee, 'myEvent');
} catch (e) {
console.log('出错', err);
}
}
run();