我有一个事件发射器(变换流),并且该事件发射器基本上有一堆子发射器。
我想将所有子发射器中的事件转发到父发射器,如下所示:
const EE = require('events');
const exportEvents = new EE();
const sumanEvents = Transform(); // create new transform stream (an event emitter)
sumanEvents.on('test', function () {
exportEvents.emit.bind(exportEvents, 'test').apply(exportEvents, arguments);
});
sumanEvents.on('error', function () {
exportEvents.emit.bind(exportEvents, 'error').apply(exportEvents, arguments);
});
sumanEvents.on('suman-test-file-complete', function () {
exportEvents.emit.bind(exportEvents, 'suman-test-file-complete').apply(exportEvents, arguments);
});
基本上,据我所知,我已将错误,测试和suman-test-file-complete事件转发给父级,但这看起来非常难看。
至少有一种更复杂的方法吗?我假设没有办法直接用Node.js'events'包继承事件,所以我不是在问这个问题。
答案 0 :(得分:2)
您可以覆盖sumanEvents.emit()
,这样您就可以看到发出的任何事件,然后抓住它并将其回显到exportEvents
:
(function(origEmitter, forwardEmitter) {
// save original .emit method
let oldEmit = origEmitter.emit;
// assign override
origEmitter.emit = function() {
// allow the event to be normally emitted
oldEmit.apply(origEmitter, arguments);
// then forward it to the forwardEmitter
forwardEmitter.emit.apply(forwardEmitter, arguments);
};
})(sumanEvents, exportEvents);
或者,放入可重复使用的函数表单,以便在不复制代码的情况下在多个发射器上使用它:
function forwardEmitter(origEmitter, forwardEmitter) {
// save original .emit method
let oldEmit = origEmitter.emit;
// assign override
origEmitter.emit = function() {
// allow the event to be normally emitted
oldEmit.apply(origEmitter, arguments);
// then forward it to the forwardEmitter
forwardEmitter.emit.apply(forwardEmitter, arguments);
};
}
forwardEmitter(sumanEvents, exportEvents);
如果你想更容易地重用它,可以将这个功能封装在一个派生自EventEmitter
的新对象中,但这只有在你控制第一个EventEmitter对象的创建时才有效使其成为支持转发所有消息的特殊派生对象。上面的示例可以“添加”到任何现有的常规EventEmitter
对象。
还有一个EventEmitter2
对象described here,它允许您使用通配符来注册事件处理程序,这样您就可以注册所有事件或事件子集的兴趣,而无需单独命名每个事件。 / p>
并且,在Google邮件列表上讨论了这个概念:https://groups.google.com/forum/#!topic/nodejs-dev/TzRPxsHf0FA
答案 1 :(得分:0)
但这看起来很丑。
您绑定并申请的原因是否存在?看来这些被错误地使用了。像exportEvents.emit.bind(exportEvents, 'test').apply(exportEvents, arguments)
这样的行可以简化为EE.emit.apply(exportEvents, 'test', arguments)
,或者使用扩展语法,exportEvents.emit('test', ...arguments)
话虽如此,实用程序功能在这里可能会有所帮助。 jfriend00's above solution可以,但是我真的不喜欢它会覆盖原始对象上的方法(即使正在调用原始方法)。
实际上,另一种解决方案更简单(更少的代码行):
function forwardEvent(emitterToListenOn, emitterToEmitOn, event) {
emitterToListenOn.on(event, function() { //can't use arrow here, as we need 'arguments'
emitterToEmitOn.emit(event, arguments);
});
}
function forwardEvents(emitterToListenOn, emitterToEmitOn, events) {
events.forEach(event => forwardEvent(emitterToListenOn, emitterToEmitOn, event));
}
function forwardEventsToMultipleEmitters(emitterToListenOn, emittersToEmitOn, events) {
emittersToEmitOn.forEach(emitterToEmitOn => forwardEvents(emitterToListenOn, emitterToEmitOn, events));
}
对于那些不喜欢使用箭头功能的人,下面是相同的代码,但没有:
function forwardEvent(emitterToListenOn, emitterToEmitOn, event) {
emitterToListenOn.on(event, function() { //can't use arrow here, as we need 'arguments'
emitterToEmitOn.emit(event, arguments);
});
}
function forwardEvents(emitterToListenOn, emitterToEmitOn, events) {
events.forEach(function(event) {
forwardEvent(emitterToListenOn, emitterToEmitOn, event);
});
}
function forwardEventsToMultipleEmitters(emitterToListenOn, emittersToEmitOn, events) {
emittersToEmitOn.forEach(function(emitterToEmitOn) {
forwardEvents(emitterToListenOn, emitterToEmitOn, events);
});
}
要在原始代码中使用它们,
const EE = require('events');
const exportEvents = new EE();
const sumanEvents = Transform(); // create new transform stream (an event emitter)
forwardEvents(sumanEvents, exportEvents, ['test', 'error', 'suman-test-file-complete']);
此forwardEvent
比jfriend00的forwardEmitter
少了几行代码,并且没有覆盖任何功能,最终的解决方案对我来说似乎很干净。