NodeJS:一个全局事件发射器或它自己的每个模块?

我目前正计划在NodeJS中创build一个浏览器游戏。 游戏将基本上使用事件模块之间的每个通信。

什么是更高性能(或有优点或缺点?):

我只使用一个(全球?)EventEmitter。 每个模块都可以监听全局事件stream或者在全局事件stream中发送事件。 我会使用更复杂的事件名称,所以当事件被触发时,并不是全局事件stream中的所有侦听器都被调用。 我在单个事件stream上拥有非常多的侦听器。

例如:Player1收到一个项目。 事件“player1:inventory:item”被触发,并且只有player1在全局事件stream上监听该事件。

要么

它自己的每个模块扩展events.EventEmitter,并只提供该特定对象的事件。 每个EventEmitter上的监听器数量非常低,大部分时间只有一个监听器。

例如:一个玩家有一个questlog和一个库存。 对于每个玩家我创build一个questlog和库存的实例,把它们保存在一个集合(或玩家对象)中。 player1的任务日志只监听player1的库存。


我没有NodeJS中的EventEmitter的经验,只知道有一个警告,因为内存泄漏,在一个eventemitter或event上有10多个listener,但我不知道为什么。

我在这两个系统上看到了一些优点和缺点,但在技术方面我需要build议。

感谢您的帮助!

这取决于您在应用程序中使用的事件样式或事件样式组合。 如果您使用的是多个订阅者订阅频道/主题并且多个发布者发布到该频道/主题的广播样式,那么EventEmitter实例必须以发行者和订阅者的“全局”的方式存在。 以广播的方式,发布者和订阅者都不需要彼此了解。

如果你的事件是更多的点对点的风格,每个订阅者订阅它所引用的发布者,那么订阅者必须知道发布者,并且发布者必须在发布者之前被实例化。

这两种风格都可以通过全局单例EventEmitter(使用事件命名空间)或每个模块EventEmitter来实现,但是全局的EventEmitter更适合于广播风格,并且每个模块的EventEmitter对于点对点更自然-点。

那么我认为扩展Eventemitter你的模块肯定是更好的。 你会这样做。 这是模块编写者的常见模式。

var EventEmitter = require('events').EventEmitter; var util = require('util'); function YouEmitter() { EventEmitter.call(this); } util.inherits(YourEmitter, EventEmitter); 

这样做有很多原因,但是有很多事实背景的资源。 Mozilla的Node Holidy Season Series可能就是一个很好的例子 。

  1. 你可能不担心你增加的内存占用,但V8是。 (V8是Node运行的引擎)。随着泄漏的增加,V8在垃圾收集方面变得越来越积极,使你的应用程序变慢。 所以在Node中,内存泄漏会损害性能。
  2. 泄漏可能引发其他types的故障。 漏洞代码可能会引用有限的资源。 您可能会用完文件描述符; 您可能突然无法打开新的数据库连接。 这类问题可能会在你的应用程序耗尽内存之前就出现,而且还会让你死在水中。

  3. 最后,你的应用迟早会崩溃。 而且你可以打赌,当你受欢迎的时候,它就会发生。 然后每个人都会笑,在黑客新闻上说你的意思,你会伤心的。

除了垃圾收集,其他组件的随机故障,我认为最后一点是最有趣的:这可能是坏的风格。 当Node是相反的时候,它会使你的应用程序很重。

还调用呼叫build设者是非常昂贵的。

另一个原因是debugging内存泄漏和相关的故障并不是微不足道的debugging(从我看到的SO)来看。 当eventemitter泄漏时,由于它阻塞了事件循环,所以它真的变成了弹道。

许多其他基于事件的库(如Seneca和ZMQ)允许其事件客户端接收所有发出的事件。 他们将确定他们是否应该是一个模式的行动,例如事件的有效负载是否对他们感兴趣或ID匹配等。

按事件名称区分可能是最简单的(如下所示):

 var EventEmitter = require('events').EventEmitter; var ee = new EventEmitter(); var eNR2 = '2'; ee.on('event'+ eNR2, function(){ console.log('Event 2 has fired!')}); ee.emit('event2');