问题
Is there a way to access to the class context in the event listener method with possibility to remove the listener?
Example 1:
import {EventEmitter} from "events";
export default class EventsExample1 {
private emitter: EventEmitter;
constructor(private text: string) {
this.emitter = new EventEmitter();
this.emitter.addListener("test", this.handleTestEvent);
this.emitter.emit("test");
}
public dispose() {
this.emitter.removeListener("test", this.handleTestEvent);
}
private handleTestEvent() {
console.log(this.text);
}
}
In this example removing the listener works, but the handleTestEvent()
method has no access to the class context using this
. this
points to EventEmitter context, so this.text
is not accessible.
Example 2:
import {EventEmitter} from "events";
export default class EventsExample2 {
private emitter: EventEmitter;
constructor(private text: string) {
this.emitter = new EventEmitter();
this.emitter.addListener("test", this.handleTestEvent.bind(this));
this.emitter.emit("test");
}
public dispose() {
this.emitter.removeListener("test", this.handleTestEvent);
}
private handleTestEvent() {
console.log(this.text);
}
}
In this example, I'm using the bind function to bind a context of the class to the event listener. Now handleTestEvent
method has access to the class context using this
=> this.text
is accessible, but listener cannot be removed with removeListener - it seems that bind
creates a new anonymous function, so there is no reference to the bounded listener.
Example 3:
import {EventEmitter} from "events";
export default class EventsExample3 {
private emitter: EventEmitter;
constructor(private text: string) {
this.emitter = new EventEmitter();
this.emitter.addListener("test", () => this.handleTestEvent());
this.emitter.emit("test");
}
public dispose() {
this.emitter.removeListener("test", this.handleTestEvent);
}
private handleTestEvent() {
console.log(this.text);
}
}
In this example, I'm using an arrow function to preserve a context of the class in the event listener. handleTestEvent
method has access to the class context using this
, but listener cannot be removed (there is no reference to the bounded listener as in example 2).
I've tried an alternative event library - EventEmitter3 which has a support for custom context for events (class context can be passed as third parameter to the addListener
function (this.emitter.addListener("test", this.handleTestEvent, this
), it works perfectly, but I rather want to use the included EventEmitter from Node.js.
回答1:
You could do this in the constructor:
this.handleTestEvent = this.handleTestEvent.bind(this);
this.emitter.addListener("test", this.handleTestEvent);
If you want to use cutting edge, you can use the proposed bind operator as a shortcut:
this.handleTestEvent = ::this.handleTestEvent;
this.emitter.addListener("test", this.handleTestEvent);
Or use a property initializer to create a bound method:
constructor(private text: string) {
this.emitter = new EventEmitter();
this.emitter.addListener("test", this.handleTestEvent);
this.emitter.emit("test");
}
handleTestEvent = () => {
console.log(this.text);
}
回答2:
I was also unable to remove the listener in a class. This worked for me (see: https://nodejs.org/api/events.html#events_emitter_rawlisteners_eventname)
emitter.on('error', this.onError.bind(this));
this.onErrorListener = emitter.rawListeners('error').splice(-1)[0];
...
emitter.off('error', this.onErrorListener);
回答3:
You probably sorted this out but you could just have done
import {EventEmitter} from "events";
class HasEvents extends EventEmitter {}
const emitter = new HasEvents();
来源:https://stackoverflow.com/questions/39820651/node-js-eventemitter-how-to-bind-a-class-context-to-the-event-listener-and-then