Javascript事件发射器一次处理多个事件
Javascript eventemitter multiple events once
我正在使用节点的eventemitter
,但也欢迎其他事件库建议。
如果触发了多个事件,我想运行一次函数。应监听多个事件,但如果其中任何一个事件发生火灾,则会删除所有事件。希望这个代码示例能够展示我想要的东西。
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
// i.e., 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);
});
};
我在这里提出了一个要点: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中已经有了一个once
方法:在这里查看源代码,但这可能是最近添加的。
这样的东西怎么样:
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);
您可以围绕on
和removeAllListeners
编写一个包装器,以便能够传入数组(例如,在数组上循环并为每个元素调用on
或removeAllListeners
)。
使用Rx.Observable
:的first
运算符
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>
不幸的是,你还没有想要类似的东西。
我看了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模块中隐藏得很好,因此该模块的使用非常简单。
这里有一个通用的帮助器函数来处理这个工作流。您需要传递对事件发射器对象的引用、事件名称数组和事件处理程序函数。所有的附加、分离和传递参数到处理程序都会得到处理。
// 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();
通过这行,所有上创建的实例共享,并且与Javascript中的非标量值相同的EventEmitter始终是引用。很明显,node.js改变了一些关于模块的内部行为,就像以前一样。
解决方案是使用允许正确继承的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();
};
希望这能有所帮助。
- 主干模型更改事件只触发一次
- 如何检测滚动事件是否像在触摸设备上一样只触发一次
- 在单击事件中,第一次单击时激发代码一次,其余代码在所有单击时运行
- 简单的onclick事件只起过一次作用
- 一次点击,两次'单击'事件已启动
- Javascript事件发射器一次处理多个事件
- jQuery单击事件在一次之后不会触发
- 事件虽然注册了一次,但会触发多次
- 将触摸事件转换为鼠标事件仅每秒有效一次
- 火灾事件最多每x秒发生一次
- jQuery事件将只运行一次
- Jquery事件只工作一次
- 如何使用on()/of()激活每个事件一次
- 淘汰赛仅更新事件一次
- 元素出现后调用单击事件一次
- 带有 JSON 数据的 JavaScript Kendo 调度程序仅移动事件一次
- AngularJS-只对ng更改触发$timeout事件一次
- .一个事件一次又一次地被解雇
- 火灾调整事件一次不基于时间
- jQuery点击事件一次点击触发多次