2016-05-11 27 views
5

Ho due istanze di un oggetto che si estende EventEmitter e ascolta un evento chiamato finish. Se imposto il gestore di eventi all'esterno del costruttore, tutto funziona come previsto. Ogni istanza ascolta l'occorrenza di finish che viene attivata. Ma se imposto il gestore di eventi all'interno del costruttore, solo l'istanza creata secondo sente e reagisce all'evento, o così sembra.Il gestore eventi nel costruttore si comporta diversamente dal gestore eventi dal costruttore

Ecco il codice:

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

var NEXT_ID = 0; 
var MyEmitter = function() { 
    EventEmitter.call(this); 
    this.id = NEXT_ID; 
    NEXT_ID++; 
    console.log('CREATED EMITTER WITH ID:', this.id) 
    self = this; 
    this.on('finish', function() { 
    console.log('FINISH EVENT . CONSTRUCTOR LISTENER .', 
       'LISTENER ID:', self.id, 
       '. ORIGINATOR ID:', this.id); 
    }); 
}; 

util.inherits(MyEmitter, EventEmitter); 

var setFinishListener = function(emitter) { 
    emitter.on('finish', function() { 
    console.log('FINISH EVENT . NON-CONSTRUCTOR LISTENER .', 
       'LISTENER ID:', emitter.id, 
       '. ORIGINATOR ID:', this.id); 
    }); 
} 

var emitter0 = new MyEmitter(); 
var emitter1 = new MyEmitter(); 

setFinishListener(emitter0); 
setFinishListener(emitter1); 

emitter0.emit('finish'); 
emitter1.emit('finish'); 

// The following is logged to the console: 
// FINISH EVENT . CONSTRUCTOR LISTENER . LISTENER ID: 1 . ORIGINATOR ID: 0 
// FINISH EVENT . NON-CONSTRUCTOR LISTENER . LISTENER ID: 0 . ORIGINATOR ID: 0 
// FINISH EVENT . CONSTRUCTOR LISTENER . LISTENER ID: 1 . ORIGINATOR ID: 1 
// FINISH EVENT . NON-CONSTRUCTOR LISTENER . LISTENER ID: 1 . ORIGINATOR ID: 1 

Si noti che il LISTENER ID per la versione del gestore di eventi che è impostato all'interno del costruttore di MyEmitter appartiene sempre alla seconda istanza creato, facendo sembrare che tale istanza cattura sempre l'evento e, per qualche motivo, la prima istanza creata non ha mai attivato quel gestore.

Due fatti che io parto dal presupposto ho capito bene:

  1. this nel gestore di eventi deve essere sempre l'oggetto che ha emesso l'evento.
  2. this nel costruttore deve essere sempre l'oggetto che deve essere restituito dal costruttore (poiché viene chiamato con new).

Se entrambi questi sono veri, non so cos'altro non capisco che risultati nel comportamento esposto.

Un'altra cosa che mi ha fatto pensare: un evento dovrebbe sempre essere "ascoltato" dallo stesso EventEmitter che ha emesso l'evento? Questo è quello che ho pensato e sicuramente sembra essere il caso d'uso più comune. Ma se questa non è una limitazione, come, ad esempio, un evento click su un pulsante non attiva i gestori di clic per tutti gli altri pulsanti?

risposta

6

Il problema è che non si sta utilizzando var self = this; per applicare la variabile self all'ambito Emettitore. Quando esci dallo var, Javascript solleva la variabile fino all'ambito finché non trova un nome di variabile corrispondente dichiarato con var. Dal momento che non ne hai mai dichiarato uno, lo self sarà ospitato fino all'ambito globale, e quindi ogni emettitore verrà creato con lo stesso riferimento.

L'aggiunta di var self = this risolverà il problema. È inoltre possibile aggiungere use strict per rilevare questo tipo di problemi, in quanto non consente di dichiarare una variabile senza utilizzare var.

+0

Non riesco a credere a quanto mi sia sembrato sciocco. Stavo cercando di sistemarlo nel vecchio codice di qualcuno e sembrava troppo profondo. Completamente mancato la mancanza di var di fronte a sé. Grazie! – spectorar

Problemi correlati