【问题标题】:Forwarding events from one event emitter to another将事件从一个事件发射器转发到另一个
【发布时间】:2017-04-12 20:59:53
【问题描述】:

我有一个事件发射器(一个转换流),而那个事件发射器基本上有一堆子发射器。

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

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 的“事件”包直接继承事件,所以我不问这个。

【问题讨论】:

    标签: javascript node.js eventemitter


    【解决方案1】:

    您可以覆盖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 允许您使用通配符来注册事件处理程序,这样您就可以通过这种方式注册对所有事件或事件子集的兴趣,而无需单独命名每个事件。


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

    【讨论】:

    • 谢谢,第一个解决方案对我来说并不容易,因为我有多个 sumanEvents 发射器,而不仅仅是一个,而且我当时没有处理所有这些不同的 sumanEvents 发射器声明了 exportEvents,如果这有意义的话,但是您的第二个解决方案可能对我有用,谢谢:)
    【解决方案2】:

    但这看起来很丑。

    您是否有理由进行绑定和申请?似乎这些使用不正确。像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 少,并且没有覆盖任何函数,最终的解决方案对我来说看起来很干净。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多