6

Is there a way to tell from within an event handler callback which function and/or object emitted (called) the event?

Here is an example program:

var EventEmitter, ee, rand, obj;
EventEmitter = require("events").EventEmitter;

ee = new EventEmitter();
ee.on('do it', cFunc);

obj = {
    maybeMe:    true,
    emitting:   function() {
                    ee.emit('do it');
                }
}
function aFunc() {
    ee.emit('do it');
}
function bFunc() {
    ee.emit('do it');
}
function cFunc() {
    console.log('Who called me to do it?  aFunc or bFunc or obj (obj.emitting)?');
}

rand = Math.random(); 

if (rand < .3) {
    aFunc();
} else if (rand < .6) {
    bFunc();
} else {
    obj.emitting();
}

Also, another use, if the source of the emitted event is from a node.js built in module. For example, 'error' events. If I use a common callback for error handling, can this callback know who emitted the event which called it?

ciso
  • 2,887
  • 6
  • 33
  • 58

2 Answers2

3

Here a solution for your particular example:

function cFunc() {
    var caller = new Error().stack.split("\n")[3].trim().substring(3).split(" (")[0];
    console.log('Who called me to do it?  aFunc or bFunc or obj (obj.emitting)?');
    console.log(caller);
}

explanation

We use Error to get current stack (more info). The stack is represented as a string - the fourth line represents the calling function.

Community
  • 1
  • 1
artur grzesiak
  • 20,230
  • 5
  • 46
  • 56
  • That stack variable even gives me a line number so I can tell where in the function the emit happened. Very nice and useful for debugging. Hope you get 100 rep from me. Well earned. – ciso Apr 08 '14 at 15:44
  • Further research leads to a Ryan Dahl quote "the number one Achilles heal of it" (node style development) is the lack of a complete stack trace. console.trace and http://nodejs.org/illuminati0.pdf appear useful in this respect. I post these in case others find them useful. – ciso Apr 08 '14 at 16:09
1

Yes, this in the event listener function will refer to the EventEmitter object that emitted the event. In general though, using this may not be a good idea since it may not represent the full object you are interested in. Instead you can just reference the original object via closure, like so:

object.on('event', function() {
  var value = object.value;
});
yed
  • 322
  • 2
  • 5
  • I'm not sure I understand what you are trying to do. The event is always emitted by the object to which you attached the listener, so when you attach the listener you have access to the object as shown. The function is always 'emit'. Perhaps an example of what event specifically you are handling and what exact object you want to see would help. – yed Apr 08 '14 at 14:25
  • If the EventEmitter object is your own code, then you can pass the function name as a parameter. The idea of 'which function called me' is nebulous, there may be many functions in the stack. The object itself is accessible via 'this' or 'ee' in cFunc. – yed Apr 08 '14 at 14:41
  • Can you update your example to show exactly what built in event you are capturing and what information you want from it and for what purpose? – yed Apr 08 '14 at 14:48
  • It's not any specific built-in event. I'm asking a general question about event listeners and callbacks. The above example program shows the concept. Can cFunc tell within itself during any given invocation who called it (by function name, by line number, or by a built in function property) and if so, how? – ciso Apr 08 '14 at 15:00
  • 1
    Built in modules usually use process.nextTick for event callbacks, so you can't rely on a stack trace in general. If you're capturing an error event, then the passed in error object can give you this info via the `stack` variable on the error object. – yed Apr 08 '14 at 15:56