我目前正计划在NodeJS中创建一个浏览器游戏。游戏将基本上使用事件进行模块之间的每次通信。
我只使用一个(全局?)EventEmitter。每个模块都可以侦听该全局事件流或在全局事件流中发出事件。我会使用更复杂的事件名称,因此当触发事件时,不会调用全局事件流上的所有侦听器。我在一个事件流中拥有非常多的侦听器。
示例:Player1收到一个项目。触发事件“player1:inventory:item”,只有player1在全局事件流上侦听该事件。
它自己的每个模块都扩展了events.EventEmitter并仅提供该特定对象的事件。每个EventEmitter上的侦听器数量非常少,大多数时候只有一个侦听器。
示例:单个玩家拥有任务日志和广告资源。对于每个玩家,我创建了一个questlog和inventory的实例,将它们保存在一个集合(或播放器对象)中。 player1的任务日志只监听player1的库存。
我对NodeJS中的EventEmitter没有经验,只知道当一个eventemitter或事件因为内存泄漏而有超过10个侦听器时会发出警告,但我不知道为什么。
我看到两个系统都有一些优点和缺点,但在技术方面我需要建议。
感谢您的帮助!
答案 0 :(得分:1)
我觉得为你的模块扩展Eventemitter肯定更好。你这样做。这是模块编写者的常见模式。
var EventEmitter = require('events').EventEmitter;
var util = require('util');
function YouEmitter() {
EventEmitter.call(this);
}
util.inherits(YourEmitter, EventEmitter);
有很多理由要这样做,但资源很少,背景很难。一个非常好的可能就是Mozilla的Node Holidy Season Series。
- 你可能不会担心你的内存占用增加,但V8是。 (V8是Node运行的引擎。)随着泄漏的增加,V8对垃圾收集变得越来越积极,从而减慢了应用程序的速度。所以在Node中,内存泄漏会影响性能。
泄漏可能会触发其他类型的故障。漏洞代码可以依赖于对有限资源的引用。你可能用完了文件描述符;您可能突然无法打开新的数据库连接。这种问题可能会在您的应用程序内存耗尽并且仍然让您死于水中之前很久就会出现。
- 醇>
最后,您的应用迟早会崩溃。你可以打赌它会在你受欢迎的那一刻发生。然后每个人都会在Hacker News上大笑并说出你的意思,你会感到难过。
除了垃圾收集,其他组件的随机故障,我认为最后一点是最有趣的:它可能是糟糕的风格。当Node是相反的时候,它会让你的应用变得更重。
同样调用callings构造函数非常昂贵。
另一个原因是调试内存泄漏和相关故障对调试来说并不容易(从我在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');
答案 1 :(得分:1)
这取决于您在应用程序中使用的事件样式或事件样式的混合。如果您使用的是多个订阅者订阅频道/主题并且多个发布者发布到该频道/主题的广播样式,那么EventEmitter实例必须存在于其发布者和订阅者的“全局”内容中。通过广播风格,发布者和订阅者都不需要彼此了解。
如果您的活动是更加点对点的风格,其中每个订阅者订阅了它所引用的发布者,那么订阅者必须知道发布者,并且发布者必须在发布者之前进行实例化。 / p>
两种样式都可以通过全局单例EventEmitter(使用事件名称空间)或每个模块EventEmitter来实现,但全局EventEmitter更适合广播样式,并且每模块EventEmitter对于点对点。