簡體   English   中英

如何讓EventEmitter監聽Node.js中的另一個EventEmitter?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM