Gibt es in Node.js eine Möglichkeit, alle von einem EventEmitter-Objekt ausgegebenen Ereignisse abzuhören?
zB kannst du so etwas machen wie ...
event_emitter.on('',function(event[, arg1][, arg2]...) {}
Die Idee ist, dass ich alle Ereignisse, die von einer Serverseite ausgespuckt wurden EventEmitter
, JSON.stringify
die Ereignisdaten erfassen, über eine Websockets-Verbindung senden, sie auf der Clientseite als Ereignis reformieren und dann auf das Ereignis auf der Clientseite reagieren möchte .
javascript
json
events
node.js
Chris W.
quelle
quelle
Antworten:
Wie bereits erwähnt, befindet sich dieses Verhalten nicht im Kern von node.js. Sie können jedoch EventEmitter2 von hij1nx verwenden:
https://github.com/hij1nx/EventEmitter2
Mit EventEmitter wird kein vorhandener Code beschädigt, es werden jedoch Namespaces und Platzhalter unterstützt. Zum Beispiel:
server.on('foo.*', function(value1, value2) { console.log(this.event, value1, value2); });
quelle
emitter.onAny(listener)
Methode, die einen Listener hinzufügt, der ausgelöst wird, wenn ein Ereignis ausgegeben wird.onAny
Ereignisnamen übergeben? Weil ich es versucht habeobj.onAny(function() {console.log(arguments);});
und nur Ereignisparameter ohne Namen bekommen habe ...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 Emitters, mit dem Sie alle Ereignisse erfassen möchten, ganz einfach 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 ein ziemlich einfacher Code, der auf jedem Emitter funktionieren sollte.
quelle
Mit ES6-Klassen ist es sehr einfach:
class Emitter extends require('events') { emit(type, ...args) { console.log(type + " emitted") super.emit(type, ...args) } }
quelle
instance.prototype.emit
Funktion patchenBeachten Sie, dass alle oben beschriebenen Lösungen, die möglicherweise funktionieren, eine Art Hacking für die interne Implementierung von node.js EventEmitter beinhalten.
Die richtige Antwort auf diese Frage wäre: Die Standard-EventEmitter-Implementierung unterstützt dies nicht. Sie müssen sie umgehen .
Wenn Sie sich den Quellcode von node.js für EventEmitter ansehen, werden Sie feststellen, dass ein Listener, der keinem bestimmten Ereignistyp zugeordnet ist, ohne weitere Aktion zurückgegeben wird, da versucht wird, die Rückruffunktion aus einem Hash abzurufen basierend auf dem Ereignistyp:
https://github.com/nodejs/node/blob/98819dfa5853d7c8355d70aa1aa7783677c391e5/lib/events.js#L176-L179
Deshalb
eventEmitter.on('*', ()=>...)
kann so etwas nicht standardmäßig funktionieren.quelle
Seit Node.js v6.0.0 wird der neue
class
Syntax- und Argumentverbreitungsoperator vollständig unterstützt, sodass es ziemlich sicher und ziemlich einfach ist, 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 basiert auf der Tatsache, dass die ursprüngliche
emit
Methode derEventEmitter
Rückgabetrue
/false
abhängig davon ist, ob das Ereignis von einem Listener behandelt wurde oder nicht. Beachten Sie, dass die Überschreibung einereturn
Anweisung enthält, sodass wir dieses Verhalten für andere Verbraucher beibehalten.Hier besteht die Idee darin, mit dem star event (
*
) Handler zu erstellen, die für jedes einzelne Ereignis (z. B. zu Protokollierungszwecken) und für das leere Ereignis (z.''
) für einen Standard- oder catch all-Handler, der ausgeführt wird, wenn nichts anderes dies abfängt Veranstaltung.Wir stellen sicher, dass das
*
Ereignis star ( ) zuerst aufgerufen wird , da beierror
Ereignissen ohne Handler das Ergebnis tatsächlich eine Ausnahme ist, die ausgelöst wird. Weitere Informationen finden Sie in der Implementierung desEventEmitter
.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 bereits eine EventEmitter-Instanz vorhanden ist, Sie diese bestimmte Instanz jedoch an das neue Verhalten anpassen möchten, können Sie dies einfach tun, indem Sie die Methode zur Laufzeit wie folgt patchen:
quelle
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); } }
quelle
Ich musste alle ausgegebenen Ereignisse in allen Bibliotheken verfolgen, also tippte ich auf die
prototype
.In diesem Beispiel wird a verwendet
Typescript signature
, aber Sie können es einfach entfernen, wenn Sie sich nicht für diese Art von Unsinn interessieren.this
Bezieht sich innerhalb des Aufrufs auf das Objekt, das emittiert. Es war sehr einfach, alle eindeutigen Objekte zu verfolgen: Emits 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 basierend auf dem Ereignisnamen oder Klassennamen filtern.
quelle
Möglicherweise möchten Sie RPC-Module für node.js untersuchen. Wenn ich mich nicht irre, verfügt das Dnode-RPC-Modul über ein Chat-Server / Client-Beispiel, das dem ähnelt, was Sie versuchen. Sie können also entweder ihr Modul verwenden oder kopieren, was sie tun.
In Kürze zeigt das Beispiel einen Server, der bei Verbindung Listener für alle Serverereignisse vom verbundenen Client erstellt. Dazu wird einfach eine gespeicherte Liste von Ereignisnamen durchlaufen.
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 beim Auslösen des Ereignisses automatisch einen Remoteprozeduraufruf auf dem dem Ereignis zugeordneten Client aufruft.
quelle
Ist heute auf dasselbe Problem gestoßen, hier ist 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); } }));
quelle
Ein Affen-Patch fügt EventEmitter eine beliebige 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)})
quelle
Hier ist ein Debug-Tool, das von Martins Antwort inspiriert wurde ( https://stackoverflow.com/a/18087021/1264797 ). Ich habe dies gerade verwendet, um herauszufinden, was in einer Reihe von Streams falsch lief, indem ich alle Ereignisse auf der Konsole protokollierte. Funktioniert super. Wie Martin zeigt, könnte OP es verwenden, indem der Aufruf von console.log () durch einen Websocket-Absender ersetzt wird.
function debug_emitter(emitter, name) { var orig_emit = emitter.emit; emitter.emit = function() { var emitArgs = arguments; console.log("emitter " + name + " " + util.inspect(emitArgs)); orig_emit.apply(emitter, arguments); } }
quelle
var util = require('util');
Sie können auch eine andere Event-Emitter-Implementierung wie https://github.com/ozantunca/DispatcherJS verwenden . Die Implementierung wäre wie folgt:
dispatcher.on('*', function () {});
DispatcherJS unterstützt auch Namespaces und sogar Abhängigkeiten, um zu bestimmen, welche Rückrufe zuerst aufgerufen werden.
quelle