Search code examples
javascriptnode.jseventsclosureseventemitter

Returning an object that can only receive events but not emit


Apologies if this is a duplicate, I searched the internet for hours and came up empty so I decided to post here.

I am developing a module for node.js that would have to deal with socket connections. I want to create a function that returns an object to the user that will then receive events the user can set listeners on. However, I want to do it in a way so that the user wont be able to emit events on that object. Instead, I want the emit function in my event emitter to be overwritten by my own function.

Basically, I want to return an object that receives events and has a function called "emit" that acts like any regular function.

Heres a small example of what I have in mind:

var events = require('events');

var out = (function(){
  var obj = new events.EventEmitter();

  // I used nextTick to emulate the asyncrounes nature of the socket server
  process.nextTick(function(){

    obj.emit('Message', "Dummy socket message") // This will be triggered when a message is sent to the socket server
  })

  return obj;
})();


out.on('Message', function(msg){
  console.log(msg)
  out.emit("newWork", "New instructions")
  // Im trying to make it work so that this would not throw the event emitter into an infinite loop
});

Now, in the out.on("Message", function... part I want the user to be able to write out.emit("dummy", "dummy data") and be able to call my own emit function that does something with the provided inputs.

How would I go about doing that?

I know it must be possible somehow since socket.io does exactly that. Heres a small piece of code with socket.io

socket.on('test', function(){
  console.log("called!")
})

socket.emit("test")

When I run that, it doesnt trigger itself. The emit function seems to be overwritten by something else but the socket object still receives events that are emitted from within somehow.

I hope that my explanation was sufficient. Thanks in advance!

Edit: I know that using (function() { ... })() is not the way to create modules. Im using here just to make it easier to illustrate as the concept stays the same with this approach


Solution

  • I think I figured it out on my own.

    I will overwrite the emit function in the new EventEmitter instance that I create with my own function and use the one from EventEmitter.prototype instead. That way I can ship my object back to the user with a custom emit function while still being able to emit events on that object from my module

    Here's a small demo I wrote while trying to figure this out.

    var events = require('events').EventEmitter;
    obj = new events();
    
    obj.emit = function(name, data){
      console.log("Received: name - " + name + "; data - " + data);
    }
    
    function emitOnObj(obj, name, msg){
      events.prototype.emit.call(obj, name, msg);
    }
    

    This looks pretty good to me but if there's a better way to do this then Im all ears :)