[英]How to make an EventEmitter listen to another EventEmitter in Node.js?
我想做這樣的事情:
var events = require("events");
var emitterA = new events.EventEmitter();
var emitterB = new events.EventEmitter();
emitterA.addListener("testA", function(){
console.log("emitterA detected testA");
});
emitterB.addListener("testA", function(){
console.log("emitterB detected testA");
});
emitterA.emit("testA");
輸出是這樣的:
emitterA detected testA
emitterB detected testA
但是當我運行這段代碼時,我得到的輸出是:
emitterA detected testA
我基本上想要一個發射器來監聽另一個發射器發出的事件。
理由:我在Node上編寫服務器,服務器發送Server Sent Events。 這意味着我需要持久連接。 為了確保連接沒有因某種原因而關閉(我不想將超時設置為無窮大,因為這感覺像是一個黑客並且看起來不安全),我發出一個只有空白數據的心跳,就這樣了正在傳遞給瀏覽器。
我正在運行一個計時器,每個時間段(在我的測試用例中為1秒),它將觸發server.emit("hb");
之后我同時寫入並向所有請求對象發送數據(在我的筆記本電腦上,這只是多個標簽和多個瀏覽器)。 所以基本上是req.on("hb", callback)
對我來說,這似乎更清晰,因為替代方案是為每個請求對象提供自己的計時器,這意味着將有許多計時器在各處運行,每個計時器都會導致它們各自的請求對象發出心跳事件。 這似乎是一種非理想的做事方式。
另外,因為每個請求對象都是自發創建和銷毀的,所以這樣做基本上可以確保創建和銷毀偵聽器。
所以我想要的是服務器發出的心跳事件,所有活動的請求對象都會聽到它並沿着自己的連接寫入數據。
另一個替代方案(我現在正在工作的那個)是讓服務器監聽它自己的事件,並讓服務器寫出心跳。 這個問題是服務器上的maxListeners限制 - 每個請求對象都會向服務器追加一個新的“hb”監聽器,以便服務器可以監聽該特定請求對象的事件。 但是,最大的聽眾是10,雖然我也可以將其設置為無限,但我並不太熱衷於這樣做,因為我真的好奇是否有更好的方法。
對我來說,最好和最干凈的解決方案似乎是讓請求對象“訂閱”服務器事件。 我這樣做是為了學習如何在節點中編程,所以我想盡可能少地實現外部庫並使用節點的原始功能來實現,但是如果它需要一個外部庫,我會很樂意閱讀它源代碼,這樣我就可以學習如何實現一個小的本地實現。
請注意,EventEmitters是javascript中的唯一來源。 它們不是每個人都能聽到的全系統事件。 它們是可以發出事件以支持異步模式的對象。 要完成你想要的,你需要多個東西來聽同一個發射器。 像這樣的東西:
'use strict';
var events = require( 'events' );
//Create a new sole-source event emitter
var emitterA = new events.EventEmitter();
//create a container that can listen
function EventListener( name ) {
console.log( 'new event listener, name=' + name );
this.name = name;
this.ack = function() {
console.log( this.name + ' just heard testA' );
};
this.listenTo = function( event, emitter ) {
var self = this;
emitter.on( event, function() {
self.ack();
} );
};
}
var listenerA = new EventListener( 'A', emitterA );
listenerA.listenTo( 'testA', emitterA );
var listenerB = new EventListener( 'B', emitterA );
listenerB.listenTo( 'testA', emitterA );
setInterval( function() {
emitterA.emit( 'testA' );
}, 1000 );
輸出:
$ node testfile.js
new event listener, name=A
new event listener, name=B
A just heard testA
B just heard testA
A just heard testA
B just heard testA
...
請注意,對於其他用例,您將需要使用WebSockets。 EventEmitters將無法以您希望的方式工作,尤其是遠程客戶端。 ( socket.io
的評論確實是一個很好的起點。)
您可以嘗試將事件向前發送到元素emitterB
:
emitterA.addListener("testA", function(){
console.log("emitterA detected testA");
// When everything is done emit the event to emitterB
emitterB.emit('testA');
});
或者,如果有多個事件要向前發射,您可以創建類似事件冒泡的內容:
function bubbleEvents(from, to) {
var oldEmit = from.emit;
from.emit = function (event) {
var args = Array.prototype.slice.call(arguments, 1),
newArgs = [event].concat(args);
oldEmit.apply(from, newArgs);
to.emit.apply(to, newArgs);
};
}
// and call it
bubbleEvents(emitterA, emitterB);
PS編輯像這樣的對象的方法不是一個好習慣,但是出於某些骯臟的目的,它可以很好地服務。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.