Node.jsでは、EventEmitterオブジェクトによって発行されたallイベントをリッスンする方法はありますか?
たとえば、次のようなことができますか...
event_emitter.on('',function(event[, arg1][, arg2]...) {}
アイデアは、サーバー側EventEmitter
、JSON.stringify
イベントデータから吐き出されたすべてのイベントを取得し、websockets接続を介して送信し、クライアント側でイベントとして再生成することです。 、そしてクライアント側でイベントに作用します。
前述のように、この動作はnode.jsコアにはありません。ただし、hij1nxのEventEmitter2を使用できます。
https://github.com/hij1nx/EventEmitter2
EventEmitterを使用して既存のコードを壊すことはありませんが、名前空間とワイルドカードのサポートを追加します。例えば:
server.on('foo.*', function(value1, value2) {
console.log(this.event, value1, value2);
});
私はこれが少し古いことを知っていますが、一体何があなたが取ることができる別の解決策です。
すべてのイベントをキャッチしたいエミッターの発行関数を簡単にモンキーパッチできます。
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);
}
}
これは非常に単純なコードであり、どのエミッターでも機能するはずです。
ES6クラスを使用すると、非常に簡単です。
class Emitter extends require('events') {
emit(type, ...args) {
console.log(e + " emitted")
super.emit(type, ...args)
}
}
動作する可能性のある上記のすべてのソリューションには、node.js EventEmitter内部実装に対する何らかのハッキングが含まれることに注意してください。
この質問に対する正しい答えは:デフォルトのEventEmitter実装はそれをサポートしていないので、それをハックする必要があります。
EventEmitterのnode.jsソースコードを見ると、特定のイベントタイプにリスナーがアタッチされていない場合、ハッシュからコールバック関数を取得しようとしているため、それ以上のアクションなしで戻るだけであることがわかります。イベントタイプに基づいて:
https://github.com/nodejs/node/blob/98819dfa5853d7c8355d70aa1aa7783677c391e5/lib/events.js#L176-L179
そのため、eventEmitter.on('*', ()=>...)
のようなものはデフォルトでは機能しません。
すべてのライブラリで発行されたすべてのイベントをトレースする必要があったため、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);
}
これを非常に簡単に拡張し、イベント名またはクラス名に基づいてフィルタリングできます。
これは、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);
}
}
今日同じ問題に遭遇しました、ここに解決策があります:
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);
}
}));
Node.jsのRPCモジュールを調べてください。間違っていなければ、Dnode RPCモジュールには チャットサーバー/クライアントの例 があなたがやろうとしているものに似ています。そのため、それらのモジュールを利用するか、彼らがしていることをコピーすることができます。
簡単に言うと、この例は、接続時に、接続されたクライアントからのすべてのサーバーイベントのリスナーを作成するサーバーを示しています。これは、保存されたイベント名のリストを単純に繰り返すことでこれを行います。
var evNames = [ 'joined', 'said', 'parted' ];
con.on('ready', function () {
evNames.forEach(function (name) {
emitter.on(name, client[name]);
});
emitter.emit('joined', client.name);
});
このコードは、イベントが発行されたときに、イベントに関連付けられたクライアントでリモートプロシージャコールを自動的に呼び出すため、巧妙です。
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
ステートメントが含まれていることに注意してください。したがって、この動作は他のコンシューマーにも適用されます。
ここでは、スターイベント(*
)すべての単一イベント(たとえば、ログ記録目的)および空のイベント(''
)デフォルトハンドラまたはキャッチハンドラの場合、そのイベントをキャッチするものが他にない場合に実行されます。
星(*
)最初のイベント。ハンドラーのないerror
イベントの場合、結果は実際にスローされる例外です。詳細については、 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;
モンキーパッチは、onAnyメソッドをEventEmitterに追加します。
1つの問題のイベントのみを監視できると便利です。
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)})