将事件从一个事件发射器转发到另一个事件发射器

时间:2016-11-29 01:02:06

标签: javascript node.js eventemitter

我有一个事件发射器(变换流),并且该事件发射器基本上有一堆子发射器。

我想将所有子发射器中的事件转发到父发射器,如下所示:

const EE = require('events');
const exportEvents = new EE();

const sumanEvents = Transform();     // create new transform stream (an event emitter)

sumanEvents.on('test', function () {
  exportEvents.emit.bind(exportEvents, 'test').apply(exportEvents, arguments);
});

sumanEvents.on('error', function () {
  exportEvents.emit.bind(exportEvents, 'error').apply(exportEvents, arguments);
});

sumanEvents.on('suman-test-file-complete', function () {
  exportEvents.emit.bind(exportEvents, 'suman-test-file-complete').apply(exportEvents, arguments);
});

基本上,据我所知,我已将错误,测试和suman-test-file-complete事件转发给父级,但这看起来非常难看。

至少有一种更复杂的方法吗?我假设没有办法直接用Node.js'events'包继承事件,所以我不是在问这个问题。

2 个答案:

答案 0 :(得分:2)

您可以覆盖sumanEvents.emit(),这样您就可以看到发出的任何事件,然后抓住它并将其回显到exportEvents

(function(origEmitter, forwardEmitter) {
    // save original .emit method
    let oldEmit = origEmitter.emit;

    // assign override
    origEmitter.emit = function() {
        // allow the event to be normally emitted
        oldEmit.apply(origEmitter, arguments);

        // then forward it to the forwardEmitter
        forwardEmitter.emit.apply(forwardEmitter, arguments);
    };
})(sumanEvents, exportEvents);

或者,放入可重复使用的函数表单,以便在不复制代码的情况下在多个发射器上使用它:

function forwardEmitter(origEmitter, forwardEmitter) {
    // save original .emit method
    let oldEmit = origEmitter.emit;

    // assign override
    origEmitter.emit = function() {
        // allow the event to be normally emitted
        oldEmit.apply(origEmitter, arguments);

        // then forward it to the forwardEmitter
        forwardEmitter.emit.apply(forwardEmitter, arguments);
    };
}

forwardEmitter(sumanEvents, exportEvents);

如果你想更容易地重用它,可以将这个功能封装在一个派生自EventEmitter的新对象中,但这只有在你控制第一个EventEmitter对象的创建时才有效使其成为支持转发所有消息的特殊派生对象。上面的示例可以“添加”到任何现有的常规EventEmitter对象。

还有一个EventEmitter2对象described here,它允许您使用通配符来注册事件处理程序,这样您就可以注册所有事件或事件子集的兴趣,而无需单独命名每个事件。 / p>

并且,在Google邮件列表上讨论了这个概念:https://groups.google.com/forum/#!topic/nodejs-dev/TzRPxsHf0FA

答案 1 :(得分:0)

  

但这看起来很丑。

您绑定并申请的原因是否存在?看来这些被错误地使用了。像exportEvents.emit.bind(exportEvents, 'test').apply(exportEvents, arguments)这样的行可以简化为EE.emit.apply(exportEvents, 'test', arguments),或者使用扩展语法,exportEvents.emit('test', ...arguments)

话虽如此,实用程序功能在这里可能会有所帮助。 jfriend00's above solution可以,但是我真的不喜欢它会覆盖原始对象上的方法(即使正在调用原始方法)。

实际上,另一种解决方案更简单(更少的代码行):

function forwardEvent(emitterToListenOn, emitterToEmitOn, event) {
  emitterToListenOn.on(event, function() { //can't use arrow here, as we need 'arguments'
    emitterToEmitOn.emit(event, arguments);
  });
}

function forwardEvents(emitterToListenOn, emitterToEmitOn, events) {
  events.forEach(event => forwardEvent(emitterToListenOn, emitterToEmitOn, event));
}

function forwardEventsToMultipleEmitters(emitterToListenOn, emittersToEmitOn, events) {
  emittersToEmitOn.forEach(emitterToEmitOn => forwardEvents(emitterToListenOn, emitterToEmitOn, events));
}

对于那些不喜欢使用箭头功能的人,下面是相同的代码,但没有:

function forwardEvent(emitterToListenOn, emitterToEmitOn, event) {
  emitterToListenOn.on(event, function() { //can't use arrow here, as we need 'arguments'
emitterToEmitOn.emit(event, arguments);
  });
}

function forwardEvents(emitterToListenOn, emitterToEmitOn, events) {
  events.forEach(function(event) {
forwardEvent(emitterToListenOn, emitterToEmitOn, event);
  });
}

function forwardEventsToMultipleEmitters(emitterToListenOn, emittersToEmitOn, events) {
  emittersToEmitOn.forEach(function(emitterToEmitOn) {
forwardEvents(emitterToListenOn, emitterToEmitOn, events);
  });
}

要在原始代码中使用它们,

const EE = require('events');
const exportEvents = new EE();

const sumanEvents = Transform();     // create new transform stream (an event emitter)
forwardEvents(sumanEvents, exportEvents, ['test', 'error', 'suman-test-file-complete']);

forwardEvent比jfriend00的forwardEmitter少了几行代码,并且没有覆盖任何功能,最终的解决方案对我来说似乎很干净。