2012-08-27 11 views
12

मैं नोड के ईवेंटमीटर का उपयोग कर रहा हूं हालांकि अन्य ईवेंट लाइब्रेरी सुझावों का स्वागत है।जावास्क्रिप्ट इवेंटमीटर एकाधिक घटनाएं

यदि कई घटनाओं को निकाल दिया जाता है तो मैं एक बार एक समारोह चलाने के लिए चाहता हूं। कई घटनाओं को सुनना चाहिए, लेकिन यदि घटनाओं में से कोई भी आग लगती है तो उनमें से सभी हटा दिए जाते हैं। उम्मीद है कि यह कोड नमूना दर्शाता है कि मैं क्या देख रहा हूं।

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

इसे संभालने का सबसे साफ तरीका क्या है?

नोट: बाध्य कार्यों को अलग-अलग हटाने की आवश्यकता है क्योंकि अन्य श्रोताओं को बाध्य किया जाएगा।

उत्तर

9

"बढ़ाएँ" इस तरह 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 जिसमें एक उदाहरण शामिल है (आपका उदाहरण, कुछ लॉग के साथ)

[अद्यतन] फोल

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 विधि है: lowing once की मेरी कार्यान्वयन पर आधारित एक फिल्म है कि केवल घटना है कि, बुलाया गया था के रूप में टिप्पणी में अनुरोध को दूर करता है की जाँच here the source code, लेकिन यह शायद हाल ही में एक जोड़ा है।

+0

यह वास्तव में 'removeListener' काम कर के रूप में यह पहले किया था से टूट जाता है। शायद यह जवाब ठीक करने के लिए विस्तारित किया जा सकता है। – Harry

+0

क्या आप 'removeListener' को 'ईवेंट' तर्क के रूप में भेजे गए सभी ईवेंट की बजाय केवल ईवेंट को निकालने के लिए चाहते हैं? जैसे ही मुझे आपकी इच्छा के बारे में पता चल जाएगा, मैं अपना जवाब अपडेट करूंगा। – fableal

+0

बस जो घटना भेजी गई थी वह बहुत अच्छी होगी। – Harry

3

कैसे कुछ इस तरह के बारे में:

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 प्रत्येक तत्व के लिए) ।

0

दुर्भाग्य से ऐसा कुछ भी नहीं है जैसा आप अभी तक चाहते हैं।

मैं EventEmitter2 को देखो लेकिन एक समस्या है मेरा मानना ​​है ... (#66, #31)

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

} 

तरह लग रहा है दो ईवेंट हैंडलर्स की व्यापक वांछित परिणाम पैदा करता है। आप एक सहायक EventEmitter का उपयोग कर रहे हैं लेकिन इसके विवरण CustomEventEmitter मॉड्यूल के भीतर अच्छी तरह छुपाए गए हैं, ताकि मॉड्यूल का उपयोग बहुत सरल हो।

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'); 
+0

क्या यह कॉलबैक – CMCDragonkai

+0

पर कॉल करने से पहले दोनों घटनाओं के इंतजार के द्वारा काम करता है यदि आप केवल उनमें से एक को छोड़ देते हैं, तो कॉलबैक अभी भी कॉल हो जाता है। – CMCDragonkai

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

इस लाइन सभी उदाहरणों पर बनाया हिस्सा है और एक ही EventEmitter के रूप में जावास्क्रिप्ट में गैर अदिश मूल्यों हमेशा संदर्भ हैं के साथ: समस्या यह रेखा है। स्पष्ट रूप से node.js ने मॉड्यूल के संबंध में कुछ आंतरिक व्यवहार को बदल दिया क्योंकि यह पहले काम करता था।

समाधान उपयोग कक्षा का उपयोग कर रहा है जो सही विरासत की अनुमति देता है।

require('events').EventEmitter; 
var util = require('util'); 

function Foobar = {}; 
util.inherits(Foobar, EventEmitter); 

Foobar.prototype.someMethod = function() { ... } 

module.exports.getNewFoobar = function() { 
    return new Foobar(); 
}; 

उम्मीद है कि इससे मदद मिलती है।

0

उपयोग 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>

संबंधित मुद्दे