16

ノードを使用していますがeventemitter、他のイベント ライブラリの提案を歓迎します。

複数のイベントが発生した場合に関数を 1 回実行したい。複数のイベントをリッスンする必要がありますが、いずれかのイベントが発生するとすべてが削除されます。うまくいけば、このコード サンプルは、私が探しているものを示しています。

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

これを処理する最もクリーンな方法は何ですか?

注: 他のリスナーがバインドされるため、バインドされた関数を個別に削除する必要があります。

4

7 に答える 7

10

次のように 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 には既にonceEventEmitter にメソッドがあることがわかりました:ここでソース コードを確認してください、しかしこれはおそらく最近追加されたものです。

于 2012-09-04T23:16:28.997 に答える
4

このようなものはどうですか:

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、配列を渡すことができるようにすることができます (たとえば、配列をループして各要素に対してonorを呼び出します)。removeAllListeners

于 2012-08-27T23:15:00.780 に答える
0

似たようなものに出くわしましたが、ここで共有します。それはあなたの場合にも役立つのでしょうか?

次のようなモジュールがありました。

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();
};

お役に立てれば。

于 2013-12-10T21:50:26.477 に答える
0

残念ながら、あなたが望むようなものはまだありません。

EventEmitter2を見ましたが、問題があると思います... ( #66#31 )

于 2012-09-03T19:22:46.917 に答える
0

次のアプローチはどうでしょうか

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);
        });
    }

}

2 つのイベント ハンドラーをカスケードすると、目的の結果が得られます。補助的な EventEmitter を使用していますが、その詳細は CustomEventEmitter モジュール内に隠されているため、モジュールの使用は非常に簡単です。

于 2012-09-07T09:07:07.770 に答える
0

このワークフローを処理するための一般的なヘルパー関数を次に示します。イベント エミッター オブジェクトへの参照、イベント名の配列、およびイベント ハンドラー関数を渡す必要があります。ハンドラーへの引数のアタッチ、デタッチ、および受け渡しはすべて処理されます。

// 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');
于 2012-09-07T13:41:13.637 に答える