我读了很多关于 EventEmitter
的内容,但不知道在我的 Node.js 应用程序中何时需要使用它。
我读了很多关于 EventEmitter
的内容,但不知道在我的 Node.js 应用程序中何时需要使用它。
每当代码需要订阅某些内容而不是从某些内容获取回调时,这是有意义的。典型的用例是当应用程序中有多个代码块需要在事件发生时执行某些操作。
例如,假设你正在创建一个票务系统。处理方式可能通常是这样的:
function addTicket(ticket, callback) {
insertTicketIntoDatabase(ticket, function(err) {
if (err)
return handleError(err);
callback();
});
}
但现在,有人决定当一张票据被插入数据库时,应该通过电子邮件通知用户。这没问题,你可以将它添加到回调函数中:
function addTicket(ticket, callback) {
insertTicketIntoDatabase(ticket, function(err) {
if (err)
return handleError(err);
emailUser(ticket, callback);
});
}
但现在,有人想要通知另一个系统票已经被插入。随着时间的推移,可能会发生许多该执行的操作。因此,让我们稍微修改一下:
function addTicket(ticket, callback) {
insertTicketIntoDatabase(ticket, function(err) {
if (err)
return handleError(err);
TicketEvent.emit('inserted', ticket);
callback();
});
}
我们不再需要等待所有这些函数完成后才通知用户界面。在您的代码其他位置,您可以轻松地添加这些函数:
TicketEvent.on('inserted', function(ticket) {
emailUser(ticket);
});
TicketEvent.on('inserted', function(ticket) {
notifySlack(ticket);
});
当同一事件可能发生多次或根本不发生时,应该使用EventEmitter。实际上,期望回调被调用恰好一次,无论操作是否成功。回调意味着在准备就绪时给我打电话。
使用回调的API只能通知一个特定的回调函数,而使用EventEmitter可以注册多个监听器以处理相同的事件。
如果需要通知用户状态更改,请使用事件发射器。
为了测试目的,如果要确保在函数内调用另一个函数,请发出事件。
/**
* When event listeners execute synchronous blocking code as seen in this example,
* the next listener is not notified until the first listener completes execution
* of the synchronous blocking code.
*
* Here is an output from running this code:
*
* 11:16:40 Listener 1 - processing event
* 11:16:45 Listener 1 - processed: Test Event
* 11:16:45 Listener 2 - processing event
* 11:16:45 Listener 2 - processed: Test Event
*/
const { EventEmitter } = require('events');
const time = () => {
const currentDate = new Date();
return `${currentDate.getHours()}:${currentDate.getMinutes()}:${currentDate.getSeconds()}`;
};
const EventBus = new EventEmitter();
// Listener 1
EventBus.on('event', (message) => {
console.log(`${time()} Listener 1 - processing event`);
for (let i = 0; i < 6e9; i += 1) {
// Intentionally empty
}
console.log(`${time()} Listener 1 - processed: ${message}`);
});
// Listener 2
EventBus.on('event', (message) => {
console.log(`${time()} Listener 2 - processing event`);
console.log(`${time()} Listener 2 - processed: ${message}`);
});
// Emitting event
EventBus.emit('event', 'Test Event');
/**
*
* To take full advantage of EventListener the listeners should execute
* asynchronous non-blocking code. However, wrapping a synchronous code
* into an async function is not enough. The 2nd listener is still
* blocked and waiting for the async function to complete
*
* Here is an output from running this code:
* 11:13:52 Listener 1 - processing event
* 11:13:52 Listener 1 - about to await
* 11:13:57 Listener 2 - processing event
* 11:13:57 Listener 2 - processed: Test Event
* 11:13:57 Listener 1 - await completed
* 11:13:57 Listener 1 - processed: Test Event
*/
const { EventEmitter } = require('events');
const time = () => {
const currentDate = new Date();
return `${currentDate.getHours()}:${currentDate.getMinutes()}:${currentDate.getSeconds()}`;
};
const EventBus = new EventEmitter();
// Listener 1
EventBus.on('event', async (message) => {
console.log(`${time()} Listener 1 - processing event`);
async function extracted() {
for (let i = 0; i < 6e9; i += 1) {
// Intentionally empty
}
}
console.log(`${time()} Listener 1 - about to await`);
await extracted();
console.log(`${time()} Listener 1 - await completed`);
console.log(`${time()} Listener 1 - processed: ${message}`);
});
// Listener 2
EventBus.on('event', (message) => {
console.log(`${time()} Listener 2 - processing event`);
console.log(`${time()} Listener 2 - processed: ${message}`);
});
// Emitting event
EventBus.emit('event', 'Test Event');
/**
*
* To take full advantage of EventListener the listeners should execute
* asynchronous non-blocking code. Here we are using setTimeout() in order
* to execute code asynchronously.
*
* Here is an output from running this code:
*
* 11:45:54 Listener 1 - processing event
* 11:45:54 Listener 1 - about to execute setTimeout
* 11:45:54 Listener 1 - setTimeout completed
* 11:45:54 Listener 1 - processed: Test Event
* 11:45:54 Listener 2 - processing event
* 11:45:54 Listener 2 - processed: Test Event
* 11:45:59 Listener 1 - finished the long loop
*/
const { EventEmitter } = require('events');
const time = () => {
const currentDate = new Date();
return `${currentDate.getHours()}:${currentDate.getMinutes()}:${currentDate.getSeconds()}`;
};
const EventBus = new EventEmitter();
// Listener 1
EventBus.on('event', async (message) => {
console.log(`${time()} Listener 1 - processing event`);
function extracted() {
for (let i = 0; i < 6e9; i += 1) {
// Intentionally empty
}
console.log(`${time()} Listener 1 - finished the long loop`);
}
console.log(`${time()} Listener 1 - about to execute setTimeout`);
setTimeout(extracted, 0);
console.log(`${time()} Listener 1 - setTimeout completed`);
console.log(`${time()} Listener 1 - processed: ${message}`);
});
// Listener 2
EventBus.on('event', (message) => {
console.log(`${time()} Listener 2 - processing event`);
console.log(`${time()} Listener 2 - processed: ${message}`);
});
// Emitting event
EventBus.emit('event', 'Test Event');
/**
*
* To take full advantage of EventListener the listeners should execute
* asynchronous non-blocking code. Here we are using setImmediate() in order
* to execute code asynchronously.
*
* Here is an output from running this code:
*
* 12:1:3 Listener 1 - processing event
* 12:1:3 Listener 1 - about to execute setImmediate
* 12:1:3 Listener 1 - setImmediate completed
* 12:1:3 Listener 1 - processed: Test Event
* 12:1:3 Listener 2 - processing event
* 12:1:3 Listener 2 - processed: Test Event
* 12:1:9 Listener 1 - finished the long loop
*/
const { EventEmitter } = require('events');
const time = () => {
const currentDate = new Date();
return `${currentDate.getHours()}:${currentDate.getMinutes()}:${currentDate.getSeconds()}`;
};
const EventBus = new EventEmitter();
// Listener 1
EventBus.on('event', async (message) => {
console.log(`${time()} Listener 1 - processing event`);
function extracted() {
for (let i = 0; i < 6e9; i += 1) {
// Intentionally empty
}
console.log(`${time()} Listener 1 - finished the long loop`);
}
console.log(`${time()} Listener 1 - about to execute setImmediate`);
setImmediate(extracted);
console.log(`${time()} Listener 1 - setImmediate completed`);
console.log(`${time()} Listener 1 - processed: ${message}`);
});
// Listener 2
EventBus.on('event', (message) => {
console.log(`${time()} Listener 2 - processing event`);
console.log(`${time()} Listener 2 - processed: ${message}`);
});
// Emitting event
EventBus.emit('event', 'Test Event');