如何在Node.js中共享EventEmitter?

27
我希望从一个文件/模块/脚本中发出事件,并在另一个文件/模块/脚本中监听这些事件。如何在它们之间共享emitter变量而不污染全局命名空间呢?
谢谢!
3个回答

28

@srquinn是正确的,你应该使用一个共享的单例:

eventBus.js:

const EventEmitter = require('events');
const emitter = new EventEmitter();

emitter.on('uncaughtException', function (err) {
    console.error(err);
});

module.exports = emitter;

用法:

var bus = require('../path/to/eventBus');

// Register event listener
bus.on('eventName', function () {
    console.log('triggered!');
});

// Trigger the event somewhere else
bus.emit('eventName');

4
如果我有一个名为 pub.js 和另一个名为 sub.js 的文件,在其中我引用了 eventbus.js 并试图从一个文件中触发事件,从另一个文件中接收事件,即使我点赞了,它也无法正常工作。 - PirateApp
很奇怪,@PirateApp。它应该可以工作的。只需确保您在sub.js中添加事件处理程序之前在pub.js中触发事件。 - ack_inc
@ack_inc,假设PirateApp的sub.js和pub.js没有共享事件发射器模块的同一实例,这是预期行为。sub.js和pub.js必须在同一个evenBus实例上运行以互相调用。 - janithcooray

14

你可以通过以下方式向require调用传递参数:

var myModule = require('myModule')(Events)

然后在"myModule"中

module.exports = function(Events) {
    // Set up Event listeners here
}

话虽如此,如果你想要分享一个事件发射器,请创建一个发射器对象,然后通过 require 调用将其传递给你的“文件/模块/脚本”。

更新:

虽然这是正确的做法,但这是一种代码异味,因为现在你将模块紧密地耦合在一起。相反,考虑使用可以被每个模块引用的集中式事件总线。


你如何控制这些 require 的流程?比如说有 4 个文件需要它。模块只是暴露一个变量 = new EventEmitter() 吗?并且在任何人使用 requires 之前就已经被实例化了吗? - fancy
1
我刚刚实现了我描述的模式,看起来效果相当不错。我有一个名为 emitters 的模块,它公开了一个 exports.variable = new EventEmitter()。两个文件都需要这个 emitters 模块,并可以通过 variable 传递事件。 - fancy
您还可以考虑保留一个顶层模块,创建发射器对象,然后将该对象传递给需要监听“全局”事件的任何子模块(如果我敢使用那个词)。 - srquinn
我假设我描述的模式每次需要它时都会实例化一个新的EventEmitter,但它似乎不像那样运行,这真的很好。希望我没有漏掉什么。 - fancy
2
@fancy Node.js 缓存模块,因此当您第一次要求该模块时,其中的代码实际上只会运行一次。 - Aaron Dufour

12

为什么不使用全局进程对象的EventEmitter?

process.on('customEvent', function(data) {
  ...
});

process.emit('customEvent', data);

优点:您可以禁用或完全删除模块(例如跟踪器),而不必在路由中删除所有跟踪代码。我正在为 node-trackable 做这件事。

缺点:我现在不知道,但如果您发现问题,请告诉我;-)


1
事件名称可能会出现冲突,最好明确指定以避免风险。 - lsl
12
缺点:事件将被锁定到一个进程,这阻止了通过群集模块或其他方法进行横向扩展。 - srquinn
1
@jibsales 你会如何在集群中的工作进程之间共享事件发射器?集群共享服务器端口,但我不确定它们是否可以轻松共享JavaScript对象。 - wheresrhys
@Louis,除非你在命名方面小心,否则在任何共享事件发射器上都会出现问题。 - wheresrhys
1
@Sascha_Reuter 对此的一种变体可能是将自己的事件发射器分配为进程的属性。 - wheresrhys
@wheresrhys 使用某种形式的消息总线或等待Node核心中的“Domain”模块稍微成熟一些。 - srquinn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接