node.js - NodeJS 中的 EventEmitters 是否会消耗资源?
问题描述
我想知道我是否应该创建一个 EventEmitter 并将一个对象传递给它,其中将有一个键来运行回调函数中的一些代码,具体取决于对象内部的键(我将有 15 种不同的情况)或者我应该创建 15 个 eventEmitter取决于 15 个不同的消息名称?我想知道创建多个 evenEmitter 是否会减慢,占用我的 NodeJS 实例的 RAM 或 CPU 资源
像这样的东西:
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event1', (data) => console.log(data)); // receiver code
myEmitter.on('event2', (data) => console.log(data)); //receiver code
myEmitter.emit('event1','event1'); //sender code
myEmitter.emit('event2','event2'); //sender code
//event3
//event4
//...
或类似的东西:
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
let obj1 = { msgType:'event1',data:'one exemple'}; // sender code
let obj2 = { msgType:'event2',data:'another exemple'}; //sender code
myEmitter.on('event', (data) => { //receiver code
if (data.msgType=="event1"){
console.log("event1");
}
if (data.msgType=="event2"){
console.log("event2");
}
});
myEmitter.emit('event',obj1); //sender code
myEmitter.emit('event',obj2); //sender
解决方案
所有的事件发射器只是一个 Javascript 对象,它保留一个包含各种方法的侦听器的数据结构。发射器中的非活动侦听器不消耗 CPU,并且只占用与存储回调引用和它正在侦听的消息名称一样多的 RAM(因此,几乎没有 RAM)。
您可以拥有对您的代码有意义的发射器。它们既便宜又高效。从字面上看,您可以将它们视为一个静态的侦听器数组。当你这样做时.addListener()
,它会向数组中添加一个项目。当你这样做时.removeListener()
,它会从数组中删除一个项目。当您这样做时.emit()
,它会找到与该特定消息匹配的侦听器并调用它们(只是函数调用)。
还是应该根据 15 个不同的消息名称创建 15 个 eventEmitters?
eventEmitters 是为处理许多不同的消息名称而构建的。因此,仅仅因为您有 15 条不同的消息,就没有理由制作 15 个唯一的 eventEmitter。您可以轻松地使用一个 eventEmitter 并.emit()
使用所有不同的消息调用它。
制作多个 eventEmitter 的原因与代码的设计和架构有关。如果您有一个想要模块化和可重用的组件并且它使用eventEmitter
,那么它可能想要创建自己的发射器并将其提供给它的客户端,这样它就不必与其他代码有依赖关系想要使用 eventEmitter,但与此特定模块没有任何关系。因此,这是一个架构和代码组织问题,而不是运行时效率问题。只创建与您的架构自然需要的一样多的 eventEmitter,仅此而已。
我想知道创建多个 eventEmitter 是否会减慢,占用我的 NodeJS 实例的 RAM 或 CPU 资源
不,它不会。每个 eventEmitter 只需要很少的内存来初始化它的基本实例数据,但这太小了,你甚至可能无法测量 1 或这些与其中 15 个之间的差异。
我想知道我是否应该创建一个 EventEmitter 并将一个对象传递给它,其中将有一个键来运行回调函数中的一些代码,具体取决于对象内的键。
如果您愿意,您可以自由地以这种方式设计您的代码,但是您正在为自己做额外的工作并且编写的代码可能不够干净。eventEmitters 的一大优势是它们为每个单独的消息维护一组特定的侦听器。如果您使用一条通用消息,然后将实际消息嵌入到传递给.emit()
调用的对象中,那么您只是丢弃了 eventEmitter 具有的功能,并给调用代码增加了负担,以确定哪个子消息实际上是包含在这个事件中。
一般来说,这将是一种使用EventEmitter
. 相反,将实际的事件名称放在 中,.emit()
并让代码为它想要侦听的实际事件名称注册一个侦听器。
所以,在你展示的两个方案中,我非常非常喜欢第一个。这就是EventEmitters
设计的使用方式以及它们旨在帮助您的方式。在某些情况下,您必须拥有带有自己的子路由的通用消息,但除非您确定需要,否则您不应该增加额外的复杂性,并且您会丢弃 EventEmitter 将执行的功能免费为您服务。
此外,您显示此代码:
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
你是否意识到没有必要仅仅为了使用一个 EventEmitter 子类。如果您要在子类上添加或覆盖方法,您只会将其子类化。但是这段代码没有显示任何实际的新方法或覆盖,所以这样做没有意义。
如果您只想使用 EventEmitter,您只需创建一个:
const myEmitter = new EventEmitter();
推荐阅读
- docker - Go 应用程序在使用 docker-compose 运行时失败并退出,但使用 docker run 命令可以正常工作
- sql - 使用 sql null 类型的验证器?
- reactjs - 如何为 React 容器组件编写 Jest 测试用例?
- amazon-web-services - redis所有键都没有迁移到集群
- spring-batch - 如何处理整个xml然后返回片段
- java - 使用 HashMap 进行搜索
- swift - 加载 NSCollectionViewItem 时出错
- postgresql - 查询执行缓慢
- node.js - 如何刷新车把视图中的数据?
- php - 从表中选择额外的数据 [Laravel]。传递参数?