如何正确删除多个事件侦听器?

时间:2018-02-26 08:38:39

标签: javascript node.js typescript

(显然这与typescript没什么关系,只是示例代码在ts中。)

import { createWriteStream, WriteStream } from "fs";

export class Util {
    public static openWrite(path: string): Promise<WriteStream> {
        return new Promise<WriteStream>((resolve, reject) => {
            const result = createWriteStream(path);

            const onError = (err: Error) => {
                // How to remove both listeners here?
                reject(err);
            }

            const onOpen = (fd: number) => {
                // How to remove both listeners here?
                resolve(result);
            };

            result.on("error", onError);
            result.on("open", onOpen);
        }); 
    }
}

代码应该说明一切。我很难看到函数应该如何编写,以便正确处理成功和失败场景,同时确保在完成所有操作后删除所有添加的事件处理程序。

当然,总是有可能调用removeAllListeners,但这看起来像是对我的黑客攻击。

2 个答案:

答案 0 :(得分:1)

在NodeJS中,所有-Xmx14g都是Streamhttps://nodejs.org/api/stream.html#stream_stream
EventEmitter有一个名为EventEmitter的方法。因此,请尝试执行以下操作:

removeListener

答案 1 :(得分:0)

Here's what I finally went with ...

public static async openWrite(path: string): Promise<WriteStream> {
    const factory = new StreamFactory(() => createWriteStream(path));

    try {
        return await factory.get();
    } finally {
        factory.dispose();
    }
}

... with StreamFactory defined as follows:

class StreamFactory<T extends EventEmitter> {
    private stream: T;
    private onOpen: (fd: number) => void;
    private onError: (err: Error) => void;
    private readonly promise: Promise<T>;

    public constructor(create: () => T) {
        this.promise = new Promise<T>((resolve, reject) => {
            this.stream = create();
            this.onOpen = fd => resolve(this.stream);
            this.onError = err => reject(err);
            this.stream.on("open", this.onOpen).on("error", this.onError); 
        });
    }

    public get(): Promise<T> { return this.promise; }

    public dispose(): void {
        this.stream.removeListener("open", this.onOpen).removeListener("error", this.onError);
    }
}

I've tested the failure and success paths of the above and the event handlers are removed correctly in both cases. Of course, this is just a variation of Jakes answer, so +1 to him for pointing this out.

This has the advantage of not resorting to Promise.finally, which doesn't seem to be available on my platform (Node 8.x).

It appears that it is definitely not a good idea to use removeAllListeners(). At least on my platform, the library itself seems to add a listener for "open" when an error occurs. removeAllListeners() would remove that with possibly unintended consequences.