如何让EventEmitter监听Node.js中的另一个EventEmitter? [英] How to make an EventEmitter listen to another EventEmitter in Node.js?

查看:104
本文介绍了如何让EventEmitter监听Node.js中的另一个EventEmitter?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想做这样的事情:

  var events = require(events); 

var emitterA = new events.EventEmitter();
var emitterB = new events.EventEmitter();

emitterA.addListener(testA,function(){
console.log(emitterA detect testA);
});

emitterB.addListener(testA,function(){
console.log(emitterB detect testA);
});

emitterA.emit(testA);

输出为:

  emitterA检测到testA 
emitterB检测到testA

但是当我运行此代码时,我得到的输出是:

  emitterA检测到testA 

我基本上想要一个发射器来侦听另一个发射器发出的事件。



基本原理:
我正在Node上编写服务器,服务器发送Server Sent Events。这意味着我需要持久连接。为了确保连接没有因某种原因而关闭(我不想将超时设置为无穷大,因为这感觉像是一个黑客并且看起来不安全),我发出一个只有空白数据的心跳,就这样了正在传递给浏览器。



我正在运行一个计时器,每个时间段(在我的测试用例中为1秒),它将触发 server.emit(hb); 之后我同时写入并向所有请求对象发送数据(在我的笔记本电脑上,这只是多个标签和多个浏览器)。所以基本上 req.on(hb,回调)



这对我来说似乎更清洁,因为替代方案是为每个请求对象提供自己的计时器,这意味着将有许多计时器在各处运行,每个计时器都会导致它们各自的请求对象发出心跳事件。这似乎是一种非理想的做事方式。



另外,因为每个请求对象都是自发创建和销毁的,所以这样做基本上可以确保监听器是创建和销毁。



所以我想要的是服务器发出的心跳事件,所有活动的请求对象都会听到它并沿着自己的连接写入数据。 / p>

另一种选择(我现在正在工作的另一种选择)是让服务器监听自己的事件,并让服务器写出心跳。这个问题是服务器上的maxListeners限制 - 每个请求对象都会向服务器追加一个新的hb监听器,以便服务器可以监听该特定请求对象的事件。但是,最大的听众是10,虽然我也可以将其设置为无限,但我并不热衷于这样做,因为我真的很好奇是否有更好的方法。



对我来说,最好和最干净的解决方案似乎是让请求对象订阅服务器事件。我这样做是为了学习如何在节点中编程,所以我想尽可能少地实现外部库并使用节点的原始功能来实现,但是如果它需要一个外部库,我会很乐意阅读它源代码,这样我就可以学习如何实现一个小的本地实现。

解决方案

请注意,EventEmitters是一种独特的源代码。 JavaScript的。它们不是每个人都能听到的全系统事件。它们是可以发出事件以支持异步模式的对象。要完成你想要的,你需要多个东西来听同一个发射器。这样的事情:

 'use strict'; 
var events = require('events');
//创建一个新的唯一源事件发射器
var emitterA = new events.EventEmitter();

//创建一个可以监听
函数的容器EventListener(name){
console.log('new event listener,name ='+ name);
this.name = name;
this.ack = function(){
console.log(this.name +'刚刚听过testA');
};
this.listenTo = function(event,emitter){
var self = this;
emitter.on(event,function(){
self.ack();
});
};
}

var listenerA = new EventListener('A',emitterA);
listenerA.listenTo('testA',emitterA);

var listenerB = new EventListener('B',emitterA);
listenerB.listenTo('testA',emitterA);

setInterval(function(){
emitterA.emit('testA');
},1000);

输出:

  $ node testfile.js 
新事件监听器,名称= A
新事件监听器,名称= B
刚刚听到testA
B刚刚听到testA
A刚刚听到过testA
B刚刚听到testA
...

请注意,对于其他用例,您将需要使用WebSockets。 EventEmitters将无法以您希望的方式工作,尤其是远程客户端。 ( socket.io 的评论确实是一个很好的起点。)


I want to do something like this:

var events = require("events");

var emitterA = new events.EventEmitter();
var emitterB = new events.EventEmitter();

emitterA.addListener("testA", function(){
    console.log("emitterA detected testA");
});

emitterB.addListener("testA", function(){
    console.log("emitterB detected testA");
});

emitterA.emit("testA");

And the output to be this:

emitterA detected testA
emitterB detected testA

But when I run this code, the output I get is:

emitterA detected testA

I basically want one emitter to listen to events emitted by another emitter.

The Rationale: I'm writing a server on Node, and the server sends out Server Sent Events. This means I'll require persistent connections. To ensure the connection isn't closed for some reason (I don't want to set the timeout to infinity because that feels like a hack and doesn't seem safe), I send out a heartbeat with just blank data, just so something is being passed to the browser.

I'm running one timer, and every time period (1 second in my test case), it will trigger server.emit("hb"); after which I write and send data to all request objects simultaneously (on my laptop, that's just multiple tabs and multiple browsers). So basically req.on("hb", callback)

This seems cleaner, to me, because the alternative is to give each request object its own timer, meaning there will be many many timers running all over the place, each one causing their respective request objects to emit heartbeat events. It seems like a non-optimal way to do things.

Plus, because each request object is spontaneously created and destroyed, doing it that way will basically ensure that the listeners are created and destroyed too.

So what I want is on a heartbeat event emitted by the server, all request objects active will hear it and write data along their own connections.

Another alternative (the one I've gotten working right now) is to make the server listen to its own events, and make the server write the heartbeats. The problem with this is the maxListeners limit on the server -- every request object will append a new "hb" listener to the server so the server can listen on that event for that specific request object. The maximum listeners, though, is 10, and while I can set this to infinity as well, I'm not too keen on doing that as I'm genuinely curious if there could be a better method.

The best and cleanest solution to me really seems to be making the request objects "subscribe" to the server events. I'm doing this to learn how to program in node, so I'd like to implement as little external libraries as possible and do it with node's raw power, but if it takes an external library, I'd be happy to read its source code just so I can learn how to implement a small local implementation.

解决方案

Note that EventEmitters are kind of sole-source in javascript. They are not system-wide events that everyone can listen to. They are objects that can emit events to support the asynchronous patterns. To accomplish what you want, you need multiple things listening to the same emitter. Something like this:

'use strict';
var events = require( 'events' );
//Create a new sole-source event emitter
var emitterA = new events.EventEmitter();

//create a container that can listen
function EventListener( name ) {
  console.log( 'new event listener, name=' + name );
  this.name = name;
  this.ack = function() {
    console.log( this.name + ' just heard testA' );
  };
  this.listenTo = function( event, emitter ) {
    var self = this;
    emitter.on( event, function() {
      self.ack();
    } );
  };
}

var listenerA = new EventListener( 'A', emitterA );
listenerA.listenTo( 'testA', emitterA );

var listenerB = new EventListener( 'B', emitterA );
listenerB.listenTo( 'testA', emitterA );

setInterval( function() {
  emitterA.emit( 'testA' );
}, 1000 );

Outputs:

$ node testfile.js 
new event listener, name=A
new event listener, name=B
A just heard testA
B just heard testA
A just heard testA
B just heard testA
...

Note that for your additional use cases, you will want to use WebSockets. EventEmitters will not work the way you want them to, especially to remote clients. (The comment for socket.io is indeed a good place to start.)

这篇关于如何让EventEmitter监听Node.js中的另一个EventEmitter?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆