收听Node.js中的所有已发送事件

时间:2011-03-03 09:34:13

标签: javascript json events node.js

在Node.js中有没有办法监听由EventEmitter对象发出的所有事件?

例如,你能做点什么......

event_emitter.on('',function(event[, arg1][, arg2]...) {}

我的想法是,我想抓住服务器端EventEmitter吐出的所有事件,JSON.stringify事件数据,通过websockets连接发送,在客户端进行改造一个事件,然后在客户端对事件采取行动。

12 个答案:

答案 0 :(得分:67)

我知道这有点旧,但到底是什么,这是你可以采取的另一种解决方案。

您可以轻松地修补要捕获所有事件的发射器的发射功能:

function patchEmitter(emitter, websocket) {
  var oldEmit = emitter.emit;

  emitter.emit = function() {
      var emitArgs = arguments;
      // serialize arguments in some way.
      ...
      // send them through the websocket received as a parameter
      ...
      oldEmit.apply(emitter, arguments);
  }
}

这是非常简单的代码,应该适用于任何发射器。

答案 1 :(得分:38)

如上所述,此行为不在node.js核心中。但是你可以使用hij1nx的EventEmitter2:

https://github.com/hij1nx/EventEmitter2

它不会破坏使用EventEmitter的任何现有代码,但会添加对名称空间和通配符的支持。例如:

server.on('foo.*', function(value1, value2) {
  console.log(this.event, value1, value2);
});

答案 2 :(得分:13)

使用ES6课程非常简单:

class Emitter extends require('events') {
    emit(type, ...args) {
        console.log(e + " emitted")
        super.emit(type, ...args)
    }
}

答案 3 :(得分:5)

请注意,上述所有可能有效的解决方案都会涉及对node.js EventEmitter内部实现的某种黑客攻击。

这个问题的正确答案是:默认的EventEmitter实现不支持,你需要破解它

如果您查看EventEmitter的node.js源代码,您将看到当没有侦听器附加到特定事件类型时,它将返回而不进行任何进一步操作,因为它正在尝试检索回调函数来自基于事件类型的哈希:

https://github.com/nodejs/node/blob/98819dfa5853d7c8355d70aa1aa7783677c391e5/lib/events.js#L176-L179

这就是为什么像eventEmitter.on('*', ()=>...)这样的东西默认无效。

答案 4 :(得分:1)

这是基于Martin上面提供的答案。我对节点有点新意,所以我需要自己解决他的问题。最后的方法,logAllEmitterEvents是重要的一点。

var events = require('events');
var hungryAnimalEventEmitter = new events.EventEmitter();

function emitHungryAnimalEvents()
{
    hungryAnimalEventEmitter.emit("HungryCat");
    hungryAnimalEventEmitter.emit("HungryDog");
    hungryAnimalEventEmitter.emit("Fed");
}

var meow = function meow()
{
  console.log('meow meow meow');
}

hungryAnimalEventEmitter.on('HungryCat', meow);

logAllEmitterEvents(hungryAnimalEventEmitter);

emitHungryAnimalEvents();

function logAllEmitterEvents(eventEmitter)
{
    var emitToLog = eventEmitter.emit;

    eventEmitter.emit = function () {
        var event = arguments[0];
        console.log("event emitted: " + event);
        emitToLog.apply(eventEmitter, arguments);
    }
}

答案 5 :(得分:1)

我需要跟踪所有库中所有发出的事件,因此我进入了prototype

此示例使用了Typescript signature,但是如果您不喜欢这种废话,就可以将其删除。

在调用中,this是指正在发射的对象。跟踪我项目中的所有唯一对象很容易。

  // For my example I use a `set` to track unique emits.
  const items = new Set()

  const originalEmit = EventEmitter.prototype.emit;
  EventEmitter.prototype.emit = function (event: String | Symbol, ...args: any[]): boolean {

    // Do what you want here
    const id = this.constructor.name + ":" + event;
    if (!items.has(id)) {
      items.add(id);
      console.log(id);
    }

    // And then call the original
    return originalEmit.call(event, ...args);
  }

您可以很容易地扩展它并根据事件名称或类名称进行过滤。

答案 6 :(得分:0)

您可能希望查看node.js的RPC模块。如果我没弄错的话,Dnode RPC模块的chat server/client example与您尝试的类似。因此,您可以使用他们的模块或复制他们正在做的事情。

简而言之,该示例显示了一个服务器,该服务器在连接时为来自连接客户端的所有服务器事件创建侦听器。它通过简单地迭代存储的事件名称列表来实现这一点。

var evNames = [ 'joined', 'said', 'parted' ];

con.on('ready', function () {
    evNames.forEach(function (name) {
        emitter.on(name, client[name]);
    });
    emitter.emit('joined', client.name);
});

此代码很聪明,因为它会在发出事件时自动调用与事件关联的客户端上的远程过程调用。

答案 7 :(得分:0)

今天遇到了同样的问题,下面是一个解决方案:

Object.create(Object.assign({},EventEmitter.prototype, {
  _onAnyListeners:[],
  emit:function(...args){
    //Emit event on every other server

    if(this._fireOnAny && typeof this._fireOnAny === 'function'){
      this._fireOnAny.apply(this,args)
    }

    EventEmitter.prototype.emit.apply(this,args)
  },
  _fireOnAny:function(...args){
    this._onAnyListeners.forEach((listener)=>listener.apply(this,args))
  },
  onAny:function(func){
    if(typeof func !== 'function'){
      throw new Error('Invalid type');
    }
    this._onAnyListeners.push(func);
  },
  removeOnAny:function(func){
    const index = this._onAnyListeners.indexOf(func);
    if(index === -1){
      return;
    }
    this._onAnyListeners.splice(index,1);
  }
}));

答案 8 :(得分:0)

自Node.js v6.0.0起,完全支持新的class语法和参数传播运算符,因此通过简单的继承和方法覆盖实现所需的功能非常安全且相当容易:

'use strict';
var EventEmitter = require('events');

class MyEmitter extends EventEmitter {
  emit(type, ...args) {
    super.emit('*', ...args);
    return super.emit(type, ...args) || super.emit('', ...args);
  }
}

此实现依赖于以下事实:emit的原始EventEmitter方法返回true / false,具体取决于事件是否由某些侦听器处理。请注意,该替代包含一个return语句,因此我们将这种行为保留给其他使用者。

这里的想法是使用star事件(*)创建在每个事件(例如,出于记录目的)和空事件('')上默认执行的处理程序或捕获所有处理程序,如果没有其他事件捕获该事件,该处理程序将被执行。

我们确保首先调用star(*)事件,因为在error事件中没有任何处理程序的情况下,结果实际上是引发了异常。有关更多详细信息,请查看implementation of the EventEmitter

例如:

var emitter = new MyEmitter();

emitter.on('foo', () => console.log('foo event triggered'));
emitter.on('*', () => console.log('star event triggered'));
emitter.on('', () => console.log('catch all event triggered'));

emitter.emit('foo');
    // Prints:
    //   star event triggered
    //   foo event triggered

emitter.emit('bar');
    // Prints:
    //   star event triggered
    //   catch all event triggered

最后,如果一个EventEmitter实例已经存在,但您想将该特定实例调整为新的行为,则可以通过在运行时像下面这样对方法进行修补来轻松实现:

emitter.emit = MyEmitter.prototype.emit;

答案 9 :(得分:0)

猴子补丁将onAny方法添加到EventEmitter。

仅监视一个问题的事件很有用。

var EventEmitter=require('events')
var origemit=EventEmitter.prototype.emit;
Object.assign( EventEmitter.prototype, {
  emit:function(){
    if(this._onAnyListeners){
        this._onAnyListeners.forEach((listener)=>listener.apply(this,arguments))
    }
    return origemit.apply(this,arguments)
  },
  onAny:function(func){
    if(typeof func !== 'function'){
      throw new Error('Invalid type');
    }
    if(!this._onAnyListeners)this._onAnyListeners=[];
    this._onAnyListeners.push(func);
  },
  removeOnAny:function(func){
    const index = this._onAnyListeners.indexOf(func);
    if(index === -1){
      return;
    }
    this._onAnyListeners.splice(index,1);
  }
});
// usage example
//gzip.onAny(function(a){console.log(a)})

答案 10 :(得分:-1)

您还可以使用其他事件发射器实现,例如https://github.com/ozantunca/DispatcherJS。实施将如下:

dispatcher.on('*', function () {});

DispatcherJS还支持名称空间甚至依赖项,以确定首先调用哪些回调。

答案 11 :(得分:-1)

这是一个受Martin的回答(https://stackoverflow.com/a/18087021/1264797)启发的调试工具。我刚才用它来通过将所有事件记录到控制台来弄清楚一组流中出了什么问题。效果很好。正如Martin所说,OP可以通过用websocket sender替换console.log()调用来使用它。

import re
matrices = re.split('-', content)
downMatrix = [[mat.split() for mat in matrix.splitlines()][1:] for matrix in matrices]