javascript eventemitter多个事件一次

我正在使用节点的eventemitter,尽pipe欢迎其他事件库的build议。

如果有几个事件被触发,我想运行一个函数。 应该听取多个事件,但如果有任何一个事件触发,则所有事件都将被删除。 希望这个代码示例演示了我在找什么。

var game = new eventEmitter(); game.once(['player:quit', 'player:disconnect'], function () { endGame() }); 

什么是最清洁的方式来处理这个问题?

注意:由于会绑定其他监听器,因此需要单独删除绑定函数。

“扩展”EventEmitter是这样的:

 var EventEmitter = require('events').EventEmitter; EventEmitter.prototype.once = function(events, handler){ // no events, get out! if(! events) return; // Ugly, but helps getting the rest of the function // short and simple to the eye ... I guess... if(!(events instanceof Array)) events = [events]; var _this = this; var cb = function(){ events.forEach(function(e){ // This only removes the listener itself // from all the events that are listening to it // ie, does not remove other listeners to the same event! _this.removeListener(e, cb); }); // This will allow any args you put in xxx.emit('event', ...) to be sent // to your handler handler.apply(_this, Array.prototype.slice.call(arguments, 0)); }; events.forEach(function(e){ _this.addListener(e, cb); }); }; 

我在这里创build了一个要点: https : //gist.github.com/3627823其中包括一个例子(你的例子,有一些日志)

[ 更新 ]以下是对我的实施进行once ,只删除所调用的事件,如评论中所要求的那样:

 var EventEmitter = require('events').EventEmitter; EventEmitter.prototype.once = function(events, handler){ // no events, get out! if(! events) return; // Ugly, but helps getting the rest of the function // short and simple to the eye ... I guess... if(!(events instanceof Array)) events = [events]; var _this = this; // A helper function that will generate a handler that // removes itself when its called var gen_cb = function(event_name){ var cb = function(){ _this.removeListener(event_name, cb); // This will allow any args you put in // xxx.emit('event', ...) to be sent // to your handler handler.apply(_this, Array.prototype.slice.call(arguments, 0)); }; return cb; }; events.forEach(function(e){ _this.addListener(e, gen_cb(e)); }); }; 

我发现node.js在EventEmitter中已经有了一个方法: 在这里检查源代码 ,但这可能是最近的一个附加。

怎么样这样的事情:

 var game = new EventEmitter(); var handler = function() { game.removeAllListeners('player:quit'); game.removeAllListeners('player:disconnect'); endGame(); }; game.on('player:quit', handler); game.on('player:disconnect', handler); 

你可以在onremoveAllListeners on编写一个包装器,以便能够传入一个数组(例如,遍历数组并为每个元素调用removeAllListeners )。

不幸的是,你还没有想要的东西。

我看EventEmitter2,但是我相信有一个问题…( #66 , #31 )

以下方法如何?

 var myEmitter = new CustomEventEmitter; myEmitter.onceAny(['event1', 'event2', 'event3', 'event4'], function() { endGame(); }); 

当CustomEventEmitter看起来像这样

 function CustomEventEmitter() {}; // inherit from EventEmitter CustomEventEmitter.prototype = new EventEmitter; CustomEventEmitter.prototype.onceAny = function(arrayEvents, callback) { // generate unique string for the auxiliary event var auxEvent = process.pid + '-' + (new Date()).getTime(); // auxiliary event handler var auxEmitter = new EventEmitter; // handle the event emitted by the auxiliary emitter auxEmitter.once(auxEvent, callback); for (var i = 0; i < arrayEvents.length; i++) { this.once(arrayEvents[i], function() { auxEmitter.emit(auxEvent); }); } } 

两个事件处理程序的级联产生所需的结果。 您正在使用一个辅助EventEmitter,但是它的细节很好地隐藏在CustomEventEmitter模块中,所以模块的使用非常简单。

这里有一个通用的帮助函数来处理这个工作stream程。 您需要传递对事件发射器对象,事件名称数组和事件处理函数的引用。 所有的附加,分离和传递给你的处理程序的照顾都是照顾的。

 // listen to many, trigger and detach all on any function onMany(emitter, events, callback) { function cb() { callback.apply(emitter, arguments); events.forEach(function(ev) { emitter.removeListener(ev, cb); }); } events.forEach(function(ev) { emitter.on(ev, cb); }); } 

和一个用法示例:

 // Test usage var EventEmitter = require('events').EventEmitter; var game = new EventEmitter(); // event list of interest var events = ['player:quit', 'player:disconnect']; // end game handler function endGame() { console.log('end the game!'); } // attach onMany(game, events, endGame); // test. we should log 'end the game' only once game.emit('player:disconnect'); game.emit('player:quit'); 

我刚碰到类似的东西,虽然在这里分享。 可能是这也有助于你的情况?

我有一个看起来像这样的模块:

 require('events').EventEmitter; function Foobar = {}; Foobar.prototype = new EventEmitter(); Foobar.prototype.someMethod = function() { ... } module.exports.getNewFoobar = function() { return new Foobar(); }; 

有趣的是:这直到node.js 0.8.x,但不再工作。 问题是这一行:

 Foobar.prototype = new EventEmitter(); 

使用这一行,创build的所有实例共享,并且与JavaScript中的非标量值相同的EventEmitter始终是引用。 很显然,node.js改变了一些模块的内部行为。

解决scheme是使用允许正确inheritance的util类。

 require('events').EventEmitter; var util = require('util'); function Foobar = {}; util.inherits(Foobar, EventEmitter); Foobar.prototype.someMethod = function() { ... } module.exports.getNewFoobar = function() { return new Foobar(); }; 

希望这可以帮助。

使用Rx.Observablefirst运算符:

 let game = new EventEmitter(); let events = ['player:quit', 'player:disconnect']; //let myObserver = Rx.Observable.fromEventPattern(handler => { // events.forEach(evt => game.on(evt, handler)); //}).first(); let myObserver = Rx.Observable.merge(...events.map(evt => Rx.Observable.fromEvent(game, evt))).first(); myObserver.subscribe(() => { // clean up console.log('Goodbye!!'); }); game.emit('player:quit'); // Goodbye!! game.emit('player:quit'); // No output game.emit('player:disconnect'); // No output 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.0/Rx.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/EventEmitter/5.1.0/EventEmitter.min.js"></script>