首页 > 解决方案 > 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

标签: node.js

解决方案


所有的事件发射器只是一个 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();

推荐阅读