什么时候我应该使用EventEmitter
When should I use EventEmitter?
我读了很多关于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允许我们为事件注册多个监听器相同的事件。
-
如果你需要通知用户状态变化,使用事件发射器。
-
为了测试的目的,如果你想确保一个函数在函数内部被调用,触发一个事件。
Node.js事件发射器在希望将代码库分解为使用类似于发布-订阅的异步模式调用的组件或服务。然而,通常当我们谈论发布-订阅模式时,我们指的是分布式分解系统。这里的情况并非如此,因为所有组件都存在于相同的代码库中,并在相同的Node.js运行时中运行。
请记住,使用Node.js事件发射器不会使我们的代码自动非阻塞,异步。需要特别注意的是,事件侦听器(订阅者)不会相互阻塞,也就是说,事件侦听器应该异步执行代码。
此外,在使用此模式时,事件发射器(发布者)不关心事件侦听器所采取的操作的结果。没有回调或返回值。如果这些操作是关键的,则需要处理故障。
代码示例:
/**
* 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');
- 可以'I don’我不明白;使用webpack和es6模块进行EventEmitter
- 我在谷歌地图上有一个标记,点击后应该会显示文本内容
- 我该如何将onbeforeload函数应用于此javascript
- 我的应用程序中的可点击元素应始终是锚标记
- 如何将CSS样式应用于由Javascript脚本注入和样式化的HTML,这是我无法控制的
- 我可以比较两个Perl哈希(键和值)提取差异并应用于JavaScript中的哈希吗?
- 如果我使用 jQuery 的 .hide() 和 .show() 方法,如何将 javascript 验证仅应用于 HT
- 如何在我的网站中嵌入指向办公室位置的必应地图
- Chrome扩展本应在所有Facebook页面上运行,但只有当我点击刷新时才会运行
- 必应地图.我怎样才能尽快得到地址
- 选中时,ajax加载应保持我复选框的状态
- 运行我的应用时,出现了Angular模块注入错误
- 我如何使这个AJAX预过滤器只应用于GET请求
- 如何在js或css中固定图像位置?我有摩天轮,我想我所有的图像应该站的位置,而旋转
- d3js v4:我如何应用力到节点的点击,使它看起来像一个渐变
- 我如何使用本地json文件创建热图(必应地图)
- 什么时候我应该使用EventEmitter
- 我可以将所需的属性应用于 HTML 中的<选择>字段吗?
- 如果只有用户名可用,我想在 php 中启用表单字段,否则字段应保持禁用状态
- 我想验证日历作为出发和目的地日期和日期不应小于出发日期