Javascript 在 Node.js 中监听所有发出的事件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5178869/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Listen to All Emitted Events in Node.js
提问by Chris W.
In Node.js is there any way to listen to allevents emitted by an EventEmitter object?
在 Node.js 中,有没有办法监听EventEmitter 对象发出的所有事件?
e.g., can you do something like...
例如,你能不能做点像...
event_emitter.on('',function(event[, arg1][, arg2]...) {}
The idea is that I want to grab all of the events spit out by a server side EventEmitter
, JSON.stringify
the event data, send it across a websockets connection, reform them on the client side as an event, and then act on the event on the client side.
这个想法是我想获取服务器端吐出的所有事件EventEmitter
,JSON.stringify
事件数据,通过 websockets 连接发送它,在客户端将它们作为事件进行改造,然后在客户端对事件采取行动.
采纳答案by Henrik Joreteg
As mentioned this behavior is not in node.js core. But you can use hij1nx's EventEmitter2:
如前所述,这种行为不在 node.js 核心中。但是你可以使用hij1nx的EventEmitter2:
https://github.com/hij1nx/EventEmitter2
https://github.com/hij1nx/EventEmitter2
It won't break any existing code using EventEmitter, but adds support for namespaces and wildcards. For example:
它不会破坏任何使用 EventEmitter 的现有代码,但会增加对命名空间和通配符的支持。例如:
server.on('foo.*', function(value1, value2) {
console.log(this.event, value1, value2);
});
回答by Martin
I know this is a bit old, but what the hell, here is another solution you could take.
我知道这有点旧,但是到底是什么,这是您可以采用的另一种解决方案。
You can easily monkey-patch the emit function of the emitter you want to catch all events:
您可以轻松修补要捕获所有事件的发射器的发射功能:
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);
}
}
This is pretty simple code and should work on any emitter.
这是非常简单的代码,应该适用于任何发射器。
回答by pravdomil
With ES6 classes it's very easy:
使用 ES6 类很容易:
class Emitter extends require('events') {
emit(type, ...args) {
console.log(type + " emitted")
super.emit(type, ...args)
}
}
回答by David Rissato Cruz
Be aware that all solutions described above that might work will involve some sort of hacking for node.js EventEmitter internal implementation.
请注意,上述所有可能有效的解决方案都将涉及对 node.js EventEmitter 内部实现的某种黑客攻击。
The right answer to this question would be: the default EventEmitter implementation does not support that, you need to hack around it.
这个问题的正确答案是:默认的 EventEmitter 实现不支持,你需要绕过它。
If you take a look on node.js source code for EventEmitter, you will see that when no listener is attached to a specific event type, it will just return without any further action, because it is trying to retrieve the callback function from a hash based on the event type:
如果您查看 EventEmitter 的 node.js 源代码,您将看到当没有侦听器附加到特定事件类型时,它将直接返回而不采取任何进一步操作,因为它正在尝试从哈希中检索回调函数基于事件类型:
https://github.com/nodejs/node/blob/98819dfa5853d7c8355d70aa1aa7783677c391e5/lib/events.js#L176-L179
https://github.com/nodejs/node/blob/98819dfa5853d7c8355d70aa1aa7783677c391e5/lib/events.js#L176-L179
That's why something like eventEmitter.on('*', ()=>...)
can't work by default.
这就是为什么eventEmitter.on('*', ()=>...)
默认情况下不能工作的原因。
回答by Victor Schr?der
Since Node.js v6.0.0, the new class
syntax and argument spread operator is fully supported, so it's pretty safe and fairly easy to implement the desired functionality with simple inheritance and an method override:
从 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);
}
}
This implementation relies on the fact that the original emit
method of the EventEmitter
returns true
/false
depending if the event was handled by some listener or not. Notice that the override includes a return
statement, so we keep this behavior for other consumers.
此实现依赖于返回/取决于事件是否由某个侦听器处理的原始emit
方法的事实。请注意,覆盖包含一条语句,因此我们为其他消费者保留此行为。EventEmitter
true
false
return
Here the idea is to use the star event (*
) to create handlers that gets executed on every single event (say, for logging purposes) and the empty event (''
) for a default or catch all handler, that gets executed if nothing else catches that event.
这里的想法是使用星形事件 ( *
) 创建在每个事件上执行的处理程序(例如,出于记录目的)和空事件 ( ''
) 用于默认或捕获所有处理程序,如果没有其他事件捕获,则执行事件。
We make sure to call the star (*
) event first, because in case of error
events without any handlers, the result is actually an exception being thrown. For more details, take a look at the implementation of the EventEmitter
.
我们确保首先调用 star( *
) 事件,因为在error
没有任何处理程序的事件的情况下,结果实际上是抛出异常。有关详细信息,看一看的实施EventEmitter
。
For example:
例如:
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
Finally, if an EventEmitter instance already exists but you want to adjust that specific instance to the new behavior, it can be easily done by patching the method at runtime like this:
最后,如果 EventEmitter 实例已经存在,但您想将该特定实例调整为新行为,可以通过在运行时修补方法轻松完成,如下所示:
emitter.emit = MyEmitter.prototype.emit;
回答by Steven Spungin
I needed to trace all emitted events in all libraries, so I tapped into the prototype
.
我需要跟踪所有库中所有发出的事件,所以我进入了prototype
.
This example uses a Typescript signature
, but you can just remove it if you are not into that kind of nonsense.
此示例使用Typescript signature
,但如果您不喜欢那种废话,您可以将其删除。
Within the call, this
refers to the object that is emitting. It was very easy to track all unique object:emits in my project.
在调用中,this
指的是正在发射的对象。在我的项目中跟踪所有独特的 object:emits 非常容易。
// 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);
}
You can very easily extend this and filter based on event name or class name.
您可以非常轻松地扩展它并根据事件名称或类名称进行过滤。
回答by Bill Heitzeg
This is based on the answer that Martin provided above. I'm a bit new to node, so I needed to work out his answer for myself. The method at the end, logAllEmitterEvents is the important bit.
这是基于 Martin 在上面提供的答案。我对 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);
}
}
回答by Nixuz
You might want to look into RPC modules for node.js. If I am not mistaken the Dnode RPC module has an chat server/client examplesimilar to what you are trying to do. So you could either make use of their module or copy what they are doing.
您可能想查看 node.js 的 RPC 模块。如果我没记错的话,Dnode RPC 模块有一个与您尝试做的类似的聊天服务器/客户端示例。所以你可以使用他们的模块或复制他们正在做的事情。
In brief the example shows a server which on connection creates listeners for all the server events from the connected client. It does this by simply iterating over a stored list of event names.
简而言之,该示例显示了一个服务器,它在连接时为来自连接的客户端的所有服务器事件创建侦听器。它通过简单地迭代存储的事件名称列表来实现这一点。
var evNames = [ 'joined', 'said', 'parted' ];
con.on('ready', function () {
evNames.forEach(function (name) {
emitter.on(name, client[name]);
});
emitter.emit('joined', client.name);
});
This code is clever because it automatically calls a remote procedure call on the client associated with the event when the event is emitted.
这段代码很聪明,因为它会在事件发出时自动调用与事件关联的客户端上的远程过程调用。
回答by Shimon Doodkin
a monkey patch add onAny method to EventEmitter.
猴子补丁将 onAny 方法添加到 EventEmitter。
it is useful to be able to monitor only events of one problem.
能够仅监控一个问题的事件是很有用的。
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)})
回答by Eladian
Ran into the same problem today, heres a solution:
今天遇到同样的问题,解决方法如下:
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);
}
}));