Node.js EventEmitter:如何绑定一个类上下文到事件监听器,然后移除这个监听器

Node.js EventEmitter: How to bind a class context to the event listener and then remove this listener

本文关键字:监听器 js 事件 然后 上下文 何绑定 绑定 EventEmitter 一个 Node      更新时间:2023-09-26

是否有一种方法可以访问事件侦听器方法中的类上下文,并可能删除侦听器?

示例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);
    }
}

在这个例子中,删除侦听器是有效的,但是handleTestEvent()方法不能使用this访问类上下文。this指向EventEmitter上下文,因此this.text不可访问。

示例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);
    }
}

在本例中,我使用bind函数将类的上下文绑定到事件侦听器。现在handleTestEvent方法可以使用this => this.text访问类上下文,但是不能使用removeListener删除侦听器-似乎bind创建了一个新的匿名函数,因此没有对有界侦听器的引用。

示例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);
    }
}

在本例中,我使用箭头函数在事件侦听器中保存类的上下文。handleTestEvent方法可以使用this访问类上下文,但是不能删除侦听器(不像例2那样引用有界侦听器)。

我已经尝试了一个替代事件库- EventEmitter3,它支持自定义事件上下文(类上下文可以作为第三个参数传递给addListener函数(this.emitter.addListener("test", this.handleTestEvent, this),它工作完美,但我更想使用Node.js中包含的EventEmitter。

可以在构造函数中这样做:

this.handleTestEvent = this.handleTestEvent.bind(this);
this.emitter.addListener("test", this.handleTestEvent);

如果想使用cutting edge,可以使用建议的绑定操作符作为快捷方式:

this.handleTestEvent = ::this.handleTestEvent;
this.emitter.addListener("test", this.handleTestEvent);

或者使用属性初始化器创建绑定方法:

constructor(private text: string) {
  this.emitter = new EventEmitter();
  this.emitter.addListener("test", this.handleTestEvent);
  this.emitter.emit("test");
}
handleTestEvent = () => {
  console.log(this.text);
}

我也无法删除类中的侦听器。这对我有用(见: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);