Joey Yi Zhao
Joey Yi Zhao

Reputation: 42474

How to call remove listener on EventEmitter in nodejs?

I have below code to add listeners on EventEmitter,

class MyClass {
  init() {
    this.listener = new EventEmitter();
    this.listener.on('eventName', this.onChange.bind(this));
  }
  onChange() {
    ...
  }
}

How can I remove the listener from EventEmitter? I can see two different ways:

this.listener.removeListener('eventName', this.onChange)
this.listener.removeListener('eventName', this.onChange.bind(this))

I wonder which one I should use. Whether I need the bind when I remove it?

Upvotes: 4

Views: 21930

Answers (2)

peteb
peteb

Reputation: 19418

You can use bind() or you can use an Arrow Function in Node. Arrow Functions will inherit their execution context from the invoking context, which is similar to how bind() works and provides the same functionality.

this.listener.removeListener('eventName', this.onChange)

The above way of removing a listener won't work if it is being called in a removeListener(eventName) style function like the following:

const obj = new MyObject()
obj.init()
// This would blow up with a 
// ReferenceError saying you cant call removeListener() on undefined   
obj.listener.removeListener('event') 

Not sure the use of the init() function when you can use a constructor with the class syntax.

constructor() {
  this.listener = new EventEmitter()
  this.boundEventNameHandler = () => this.onChange()
  this.listener.on('eventName', this.boundEventNameHandler)
}

You can utilize the bound function for removing a listener within the context of a class using this.

let boundEventNameHandler = this.boundEventNameHandler
this.listener.removeListener('eventName', this.boundEventNameHandler)`

An example of this implemented looks like the following

const EventEmitter = require('events')

class MyObject {
  constructor () {
    this.listener = new EventEmitter()
    this.boundEventNameHandler = () => this.onChange()
    this.listener.on('eventName', this.boundEventNameHandler)
  }

  // I would reconsider making this a property of the MyObject class 
  // instead, make onChange() a local function outside the MyObject 
  // class definition because onChange in this example is only used by the 
  // event listener for 'eventName' 
  onChange () {
    console.log('event fired change')
  }

  removeListeners () {
    let boundEventNameHandler = this.boundEventNameHandler
    this.listener.removeListener('eventName', boundEventNameHandler)
  }
}

Upvotes: 6

user0103
user0103

Reputation: 1272

For TypeScript / ESNext you can use this:

class MyClass {
    constructor() {
        this.emitter = new EventEmitter();

        this.emitter.on("event1", this.listener1);
        this.emitter.on("event2", this.listener2);

        this.emitter.removeListener("event1", this.listener1);
        this.emitter.removeListener("event2", this.listener2);

        this.emitter.emit("event1"); // no output
        this.emitter.emit("event2"); // no output
    }

    public listener1 = (e) => {
        console.dir(`listener1`);
    };

    public listener2 = (e) => {
        console.dir(`listener2`);
    };
}  

Basically you define properties and instantly assign bound functions to them.
This way you use the same function reference in .on and .removeListener.

Upvotes: 0

Related Questions