admin管理员组

文章数量:1331913

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.

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.

Share edited Oct 22, 2014 at 12:41 markovchain asked Oct 20, 2014 at 12:07 markovchainmarkovchain 5031 gold badge12 silver badges26 bronze badges 4
  • FYI, socket.io already solves the problem of persistent connections to node servers and it has a messaging paradigm built-in and it's very easy to use. You can use it client to server or server to server. – jfriend00 Commented Oct 20, 2014 at 15:07
  • I'm not trying to use events across a connection, just to use them within the same module to make different objects municate – markovchain Commented Oct 22, 2014 at 12:42
  • Why is your question talking about "persistent connections" and "heatbeats" if your not doing events across a connection? Makes no sense to me. – jfriend00 Commented Oct 22, 2014 at 16:56
  • Er, sorry, you're right. I should have clarified -- I'm not trying to use //Websockets//, so I'm not intending to transmit an event from the server that can be heard from the client. I appreciate how awesome socket.io is, but in playing with node, I'm taking a look at SSEs too. So I'm trying to make an event in the server that another listener in the server can hear. It's not going to be productionized, it's curiosity. Sorry if that rates a downvote, sir... – markovchain Commented Oct 23, 2014 at 13:29
Add a ment  | 

2 Answers 2

Reset to default 4

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 acplish 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 ment for socket.io is indeed a good place to start.)

You can try to emit the event forward to the element emitterB:

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

    // When everything is done emit the event to emitterB
    emitterB.emit('testA');
});

Or if there are multiple events to emit forward you can create something like a event bubbling:

function bubbleEvents(from, to) {

    var oldEmit = from.emit;

    from.emit = function (event) {

        var args = Array.prototype.slice.call(arguments, 1),
            newArgs = [event].concat(args);

        oldEmit.apply(from, newArgs);
        to.emit.apply(to, newArgs);
    };
}

// and call it
bubbleEvents(emitterA, emitterB);

P.S. It is not a good practice to edit the methods of an object like this, but for some dirty purposes it can serve very well.

本文标签: javascriptHow to make an EventEmitter listen to another EventEmitter in NodejsStack Overflow