Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Event handler in constructor behaves differently than event handler out of constructor

I have two instances of an object that extends EventEmitter and listens to an event called finish. If I set the event handler outside the constructor everything works as expected. Each instance hears the occurence of finish that it triggers. But if I set the event handler inside the constructor, only the instance created second hears and reacts to the event, or so it seems.

Here is the code:

var util = require('util');
var EventEmitter = require('events').EventEmitter;
var fs = require('fs');

var NEXT_ID = 0;
var MyEmitter = function() {
  EventEmitter.call(this);
  this.id = NEXT_ID;
  NEXT_ID++;
  console.log('CREATED EMITTER WITH ID:', this.id)
  self = this;
  this.on('finish', function() {
    console.log('FINISH EVENT . CONSTRUCTOR LISTENER .', 
                'LISTENER ID:', self.id, 
                '. ORIGINATOR ID:', this.id);
  });
};

util.inherits(MyEmitter, EventEmitter);

var setFinishListener = function(emitter) {
  emitter.on('finish', function() {
    console.log('FINISH EVENT . NON-CONSTRUCTOR LISTENER .', 
                'LISTENER ID:', emitter.id, 
                '. ORIGINATOR ID:', this.id);
  });
}

var emitter0 = new MyEmitter();
var emitter1 = new MyEmitter(); 

setFinishListener(emitter0);
setFinishListener(emitter1);

emitter0.emit('finish');
emitter1.emit('finish');

// The following is logged to the console:
// FINISH EVENT . CONSTRUCTOR LISTENER . LISTENER ID: 1 . ORIGINATOR ID: 0
// FINISH EVENT . NON-CONSTRUCTOR LISTENER . LISTENER ID: 0 . ORIGINATOR ID: 0
// FINISH EVENT . CONSTRUCTOR LISTENER . LISTENER ID: 1 . ORIGINATOR ID: 1
// FINISH EVENT . NON-CONSTRUCTOR LISTENER . LISTENER ID: 1 . ORIGINATOR ID: 1

Notice that the LISTENER ID for the version of the event handler that is set up within the constructor of MyEmitter always belongs to the second created instance, making it seem that that instance is always catching the event first, and for some reason the first created instance never has that handler triggered.

Two facts that I am assuming I understand correctly:

  1. this in the event handler should always be the object that emitted the event.
  2. this in the constructor should always be the object to be returned by the constructor (because it is called with new).

If both of these are true I don't know what else I am not understanding that results in the exhibited behavior.

One other thing this made me think about: Should an event always be "heard" by the same EventEmitter that emitted the event? That is what I thought and certainly that seems to be the most common use case. But if that is not a restriction then how, for example, does a click event on a button not trigger the click handlers for all the other buttons?

like image 202
spectorar Avatar asked May 11 '16 13:05

spectorar


People also ask

How does an event handler behave?

In the context of the event loop, as discussed in Chapter 11, browser event handlers behave like other asynchronous notifications. They are scheduled when the event occurs but must wait for other scripts that are running to finish before they get a chance to run.

How is the event handler different from an event?

In programming, an event handler is a callback routine that operates asynchronously once an event takes place. It dictates the action that follows the event. The programmer writes a code for this action to take place. An event is an action that takes place when a user interacts with a program.

What is the use of event handlers and explain different types of event handlers?

This process of reacting over the events is called Event Handling. Thus, js handles the HTML events via Event Handlers. For example, when a user clicks over the browser, add js code, which will execute the task to be performed on the event.

Are event handlers and event listeners the same?

Note: Event handlers are sometimes called event listeners — they are pretty much interchangeable for our purposes, although strictly speaking, they work together. The listener listens out for the event happening, and the handler is the code that is run in response to it happening.


1 Answers

The issue is that you are not using var self = this; to pin the self variable to the Emitters scope. When you leave the var out, Javascript will hoist the variable up in scope until it finds a matching variable name declared with var. Since you never declared one, self will be hosted up all the way to the global scope, and thus each emitter will get created with the same reference.

Adding var self = this will solve the problem. You can also add use strict to catch these kinds of issues, as it will not allow you to declare a variable without using var.

like image 64
Mike Caputo Avatar answered Nov 15 '22 00:11

Mike Caputo