在Node.js中,有什么方法可以监听EventEmitter对象发出的所有事件?
例如,你可以做...
event_emitter.on('',function(event[, arg1][, arg2]...) {}
我的想法是,我想获取服务器端发出的所有事件EventEmitter
,JSON.stringify
事件数据,并通过websockets连接发送事件,在客户端将其重新构造为事件,然后在客户端对事件进行操作。
在Node.js中,有什么方法可以监听EventEmitter对象发出的所有事件?
例如,你可以做...
event_emitter.on('',function(event[, arg1][, arg2]...) {}
我的想法是,我想获取服务器端发出的所有事件EventEmitter
,JSON.stringify
事件数据,并通过websockets连接发送事件,在客户端将其重新构造为事件,然后在客户端对事件进行操作。
Answers:
如前所述,此行为不在node.js核心中。但是您可以使用hij1nx的EventEmitter2:
https://github.com/hij1nx/EventEmitter2
它不会使用EventEmitter破坏任何现有代码,但会增加对名称空间和通配符的支持。例如:
server.on('foo.*', function(value1, value2) {
console.log(this.event, value1, value2);
});
emitter.onAny(listener)
添加侦听器的方法,该侦听器在发出任何事件时将被激发。
onAny
传递事件名称?因为我想obj.onAny(function() {console.log(arguments);});
,我只得到了事件参数没有名字...
我知道这有点旧,但是该死,这是您可以采取的另一种解决方案。
您可以轻松地猴子想要捕获所有事件的发射器的emit函数:
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(type + " emitted")
super.emit(type, ...args)
}
}
instance.prototype.emit
功能
请注意,上述所有可行的解决方案都将涉及对node.js EventEmitter内部实现的某种黑客攻击。
这个问题的正确答案是:默认的EventEmitter实现不支持该方法,您需要解决一下。
如果您查看EventEmitter的node.js源代码,您会看到,当没有侦听器附加到特定事件类型时,它将返回而无需任何进一步的操作,因为它正在尝试从哈希中检索回调函数。根据事件类型:
https://github.com/nodejs/node/blob/98819dfa5853d7c8355d70aa1aa7783677c391e5/lib/events.js#L176-L179
这就是为什么类似的东西eventEmitter.on('*', ()=>...)
默认情况下无法工作的原因。
从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);
}
}
此实现依赖于以下事实:return /的原始emit
方法取决于事件是否由某些侦听器处理。注意,重写包含一条语句,因此我们将这种行为保留给其他使用者。EventEmitter
true
false
return
这里的想法是使用star事件(*
)创建在每个事件上执行的处理程序(例如,出于日志记录目的),而空事件(''
)创建默认的处理程序或捕获所有处理程序,如果没有其他处理程序捕获该处理程序,则执行该处理程序事件。
我们确保首先调用star(*
)事件,因为在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;
这是基于马丁上面提供的答案。我对node有点陌生,所以我需要自己解决他的问题。最后的方法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);
}
}
我需要跟踪所有库中所有发出的事件,因此我点击了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);
}
您可以很容易地扩展它并根据事件名称或类名称进行过滤。
您可能需要研究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);
});
这段代码很聪明,因为它在发出事件时自动在与事件关联的客户端上调用远程过程调用。
今天遇到同样的问题,这里有一个解决方案:
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);
}
}));
猴子补丁将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)})
这是一个受马丁回答(https://stackoverflow.com/a/18087021/1264797)启发的调试工具。我现在刚刚使用它通过将所有事件记录到控制台中来找出一组流中出了什么问题。效果很好。如Martin所示,OP可以通过使用websocket发送器替换console.log()调用来使用它。
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);
}
}
var util = require('util');
您还可以使用另一个事件发射器实现,例如https://github.com/ozantunca/DispatcherJS。实现方式如下:
dispatcher.on('*', function () {});
DispatcherJS还支持名称空间,甚至支持依赖关系,以确定哪些回调将首先被调用。