it-swarm.com.de

Hören Sie alle ausgelösten Ereignisse in Node.js

Gibt es in Node.js eine Möglichkeit, die von einem EventEmitter-Objekt ausgegebenen all - Ereignisse zu hören?

können Sie beispielsweise etwas tun ...

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

Die Idee ist, dass ich alle Ereignisse, die von einer Serverseite EventEmitter, JSON.stringify den Ereignisdaten ausgespuckt werden, mitnehmen möchte, sie über eine Websockets-Verbindung senden, sie auf der Client-Seite als Ereignis reformieren und dann das Ereignis auf der Client-Seite.

60
Chris W.

Wie bereits erwähnt, liegt dieses Verhalten nicht im node.js-Kern. Sie können jedoch EventEmitter2 von hij1nx verwenden:

https://github.com/hij1nx/EventEmitter2

Es wird keinen vorhandenen Code mithilfe von EventEmitter brechen, fügt jedoch Unterstützung für Namespaces und Platzhalter hinzu. Zum Beispiel:

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

Ich weiß, das ist ein bisschen alt, aber was solls, hier ist eine andere Lösung, die Sie nehmen könnten.

Sie können die Emit-Funktion des Senders, mit dem Sie alle Ereignisse abfangen möchten, mit einem Affen-Patch versehen:

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);
  }
}

Dies ist ziemlich einfacher Code und sollte auf jedem Emitter funktionieren.

64
Martin

Mit ES6-Klassen ist es sehr einfach:

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

Beachten Sie, dass alle oben beschriebenen Lösungen eine Art Hacking für die interne Implementierung von node.js EventEmitter beinhalten.

Die richtige Antwort auf diese Frage wäre: Die standardmäßige EventEmitter-Implementierung unterstützt das nicht, Sie müssen um sie herum hacken.

Wenn Sie einen Blick auf den Quellcode von node.js für EventEmitter werfen, werden Sie feststellen, dass, wenn kein Listener an einen bestimmten Ereignistyp angehängt ist, er ohne weitere Aktion zurückgegeben wird, da er versucht, die Rückruffunktion von einem Hash abzurufen basierend auf dem Ereignistyp: 

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

Deshalb kann so etwas wie eventEmitter.on('*', ()=>...) nicht standardmäßig funktionieren.

4

Ich musste alle emittierten Ereignisse in allen Bibliotheken nachverfolgen, also tippte ich auf die Variable prototype.

In diesem Beispiel wird ein TypeScript signature verwendet. Sie können ihn jedoch einfach entfernen, wenn Sie nicht mit diesem Unsinn konfrontiert sind.

Innerhalb des Aufrufs bezieht sich this auf das emittierende Objekt. Es war sehr einfach, alle einzigartigen Objekte zu verfolgen: emittiert in meinem Projekt.

  // 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);
  }

Sie können dies sehr einfach erweitern und nach Ereignisnamen oder Klassennamen filtern.

1
Steven Spungin

Dies basiert auf der Antwort, die Martin oben gegeben hat. Ich bin ein bisschen neu im Knoten, also musste ich seine Antwort für mich selbst herausfinden. Die Methode am Ende, logAllEmitterEvents, ist das wichtige Bit.

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);
    }
}
1
Bill Heitzeg

Hatte heute das gleiche Problem, eine Lösung:

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);
  }
}));
0
Eladian

Möglicherweise möchten Sie RPC-Module für node.js betrachten. Wenn ich mich nicht irre, hat das Dnode-RPC-Modul ein Chat-Server/-Client-Beispiel , das dem entspricht, was Sie versuchen. Sie können also entweder ihr Modul verwenden oder kopieren, was sie tun. 

Kurz gesagt zeigt das Beispiel einen Server, der bei Verbindung Listener für alle Serverereignisse des verbundenen Clients erstellt. Dies geschieht durch einfaches Durchlaufen einer gespeicherten Liste von Ereignisnamen.

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

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

Dieser Code ist clever, da er bei Aufruf des Ereignisses automatisch einen Remoteprozeduraufruf auf dem Client auslöst, der dem Ereignis zugeordnet ist.

0
Nixuz

Seit Node.js v6.0.0 wird der neue class-Syntax- und Argument-Spread-Operator vollständig unterstützt. Daher ist es ziemlich sicher und ziemlich einfach, die gewünschte Funktionalität mit einfacher Vererbung und Methodenüberschreibung zu implementieren:

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

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

Diese Implementierung beruht auf der Tatsache, dass die ursprüngliche emit-Methode der EventEmittertrue/false zurückgibt, abhängig davon, ob das Ereignis von einem Listener verarbeitet wurde oder nicht. Beachten Sie, dass die Überschreibung eine return-Anweisung enthält. Wir behalten dieses Verhalten also für andere Verbraucher bei.

Hier ist die Idee, mit dem Sternereignis (*) Handler zu erstellen, die für jedes einzelne Ereignis (z. B. zu Protokollierungszwecken) ausgeführt werden, und das leere Ereignis ('') für einen Standard- oder Catch-All-Handler, der ausgeführt wird, wenn nichts anderes ausgeführt wird fängt das Ereignis ab.

Wir stellen sicher, dass zuerst das Ereignis star (*) aufgerufen wird, da im Fall von error-Ereignissen ohne Handler das Ergebnis tatsächlich eine Ausnahme ist, die ausgelöst wird. Für weitere Details sehen Sie sich die Implementierung der EventEmitter an.

Zum Beispiel:

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

Wenn eine EventEmitter-Instanz bereits vorhanden ist, Sie diese spezifische Instanz jedoch an das neue Verhalten anpassen möchten, können Sie dies ganz einfach tun, indem Sie die Methode zur Laufzeit folgendermaßen patchen:

emitter.emit = MyEmitter.prototype.emit;
0

ein Affen-Patch fügt EventEmitter eine onAny-Methode hinzu.

es ist nützlich, nur Ereignisse eines Problems überwachen zu können.

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)})
0
Shimon Doodkin