为什么我需要在传递/暴露它时将我的EventEmitter包装在函数上?

时间:2016-03-11 17:54:31

标签: javascript node.js eventemitter

我的应用程序使用多种不同的机制与设备进行通信,例如串行(例如USB CDC /虚拟COM端口)和TCP(例如telnet),并且我试图用以下方法封装/隐藏/抽象此功能更高级别的界面,以便使用这些代码的代码的其他部分不关心使用哪种机制。

在这种情况下,我有serial.jstcp.js每个导出一个名为connect的函数,该函数返回一个具有on: function() { ... }属性的对象,我希望将其连接到他们的内部EventEmitter个实例。 (我不认为我应该暴露整个对象,因为这可能允许其他代码调用emit&创建难以调试的问题。)

令我困惑的是,如果我只是返回{ on: emitter.on },那么回调似乎永远不会被调用,但如果我返回{ on: function(a, b) { return emitter.on(a,b); }它就可以了。我觉得这与闭包/范围或符号emitter被解决的时间有关,但这与我在讨论这些主题之前遇到的其他麻烦不同。有人可以帮助我理解这里发生的事情会使这两个相似的代码行如此不同吗?

"use strict";

const net = require('net');
const EventEmitter = require('events');
const ConnectionEventNames = require('./events.js');


function connect(settings) {
    // ... (validates settings) ...
    const emitter = new EventEmitter();

    const socket = net.connect({
        host: settings.host,
        port: settings.port
    }, () => {
        emitter.emit(ConnectionEventNames.connected);
    });

    socket.on('data', (data) => {
        emitter.emit(ConnectionEventNames.received_data, data);
    });
    socket.on('error', (error) => {
        emitter.emit(ConnectionEventNames.error, error);
    });
    socket.on('end', () => {
        emitter.emit(ConnectionEventNames.disconnected);
    });
    socket.setNoDelay(settings.setNoDelay);

    return {
        // FIXME: why didn't this work the way I initially wrote it? (next line)
        on_original: emitter.on,
        on: function(eventName, listener) {
            return emitter.on(eventName, listener);
        },
        // ...
    };
}


module.exports = {
    connect
};

1 个答案:

答案 0 :(得分:1)

传递实例原型函数时的问题就是上下文丢失了。 emitter.on并非隐式绑定到emitter,它只是一个正常的函数。如果没有emitter上下文,this的实现中的.on()将无法指向您所期望的内容。

通常,您会看到异常抛出的异常,因为大多数原型函数通常都假设有效的上下文,因此尝试访问this上的特定属性,但EventEmitter有点特殊之处检查缺少的内部属性,并在它们丢失时创建它们。因此,它将在您使用(全局或其他)执行函数的任何上下文中创建这些属性。