【问题标题】:NodeJS: One Global EventEmitter or every module it's own?NodeJS:一个全局 EventEmitter 还是它拥有的每个模块?
【发布时间】:2015-03-19 16:03:19
【问题描述】:

我目前正计划在 NodeJS 中创建一个浏览器游戏。游戏将使用事件进行模块之间的几乎所有通信。

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

我只使用一个(全局?)EventEmitter。每个模块都可以监听该全局事件流或在全局事件流中发出事件。我会使用更复杂的事件名称,因此当触发事件时,不会调用全局事件流上的所有侦听器。我在一个事件流上拥有大量的侦听器。

示例:Player1 收到一个物品。事件“player1:inventory:item”被触发,并且只有 player1 在全局事件流上监听该事件。

或

它自己的每个模块都扩展了 events.EventEmitter 并仅提供该特定对象的事件。每个 EventEmitter 的监听器数量很少,大多数时候只有一个监听器。

示例:单个玩家有一个任务日志和一个库存。对于每个玩家,我都会创建一个任务日志和库存实例,将它们保存在一个集合(或玩家对象)中。 player1 的 questlog 只监听 player1 的物品栏。


我没有使用 NodeJS 中的 EventEmitter 的经验,只知道由于内存泄漏,一个事件发射器或事件上的侦听器超过 10 个时会发出警告,但我不知道为什么。

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

感谢您的每一个帮助!

【问题讨论】:

    标签: javascript node.js performance events


    【解决方案1】:

    这取决于您在应用程序中使用的事件样式或事件样式的组合。如果您使用广播风格,其中多个订阅者订阅一个频道/主题,并且多个发布者发布到该频道/主题,那么 EventEmitter 实例必须存在于对其发布者和订阅者来说是“全局”的东西中。使用广播风格,发布者和订阅者都不需要相互了解。

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

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

    【讨论】:

      【解决方案2】:

      嗯,我认为为您的模块扩展 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. 泄漏可能引发其他类型的故障。泄漏的代码可以挂在对有限资源的引用上。您可能会用完文件描述符;您可能突然无法打开新的数据库连接。这类问题可能会在您的应用程序内存不足并让您陷入困境之前很久就出现。

      3. 最后,您的应用迟早会崩溃。你可以打赌它会在你流行的那一刻发生。然后每个人都会在 Hacker News 上笑着说你的坏话,你会很难过。

      除了Garbage Collection,其他组件随机失效,我觉得最后一点是最有趣的:可能是风格不好。当 Node 正好相反时,它会让你的应用变得很重。

      调用构造函数也是非常昂贵的。

      另一个原因是调试内存泄漏和相关故障并非易事(从我在 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');
      

      【讨论】:

        猜你喜欢
        • 2013-03-16
        • 1970-01-01
        • 2013-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多