2016-05-11 10 views
5

Mam dwa wystąpienia obiektu, który rozszerza EventEmitter i nasłuchuje zdarzenia o nazwie finish. Jeśli ustawię procedurę obsługi poza konstruktorem, wszystko działa zgodnie z oczekiwaniami. Każda instancja słyszy wystąpienie finish, które wyzwala. Ale jeśli ustawię procedurę obsługi zdarzeń w konstruktorze, tylko instancja utworzona jako druga usłyszy i zareaguje na zdarzenie, lub tak się wydaje.Obsługa zdarzeń w konstruktorze zachowuje się inaczej niż obsługa zdarzeń poza konstruktorem

Oto kod:

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 

Zauważ, że LISTENER ID dla wersji obsługi zdarzeń, który jest ustawiony w ciągu konstruktor MyEmitter zawsze należy do drugiej utworzonej instancji, przez co wydaje się, że ten przykład zawsze najpierw przechwytuje zdarzenie i z jakiegoś powodu pierwsza utworzona instancja nigdy nie uruchamia tego programu obsługi.

Dwa fakty, że jestem zakładając dobrze rozumiem:

  1. this w obsłudze zdarzenia powinny zawsze być obiekt, który emitowany zdarzenie.
  2. this w konstruktorze powinien zawsze być obiektem do zwrócenia przez konstruktora (ponieważ jest wywoływany z new).

Jeśli oba te stwierdzenia są prawdziwe, nie wiem, czego jeszcze nie rozumiem, co skutkuje przedstawionym zachowaniem.

Jeszcze jedna rzecz, o której pomyślałem: czy wydarzenie powinno być zawsze "słyszane" przez tego samego EventEmittera, który emitował wydarzenie? Tak myślałem i na pewno wydaje się to najczęstszym przypadkiem użycia. Ale jeśli to nie jest ograniczenie, to jak na przykład zdarzenie click na przycisku nie wyzwala procedur obsługi kliknięć dla wszystkich pozostałych przycisków?

Odpowiedz

6

Problem polega na tym, że nie używasz var self = this; do przypinania zmiennej self do zakresu Emiterów. Po wyjściu z var na zewnątrz, JavaScript podniesie zmienną w górę, dopóki nie znajdzie pasującej nazwy zmiennej zadeklarowanej za pomocą var. Ponieważ nigdy go nie zadeklarowałeś, self będzie hostowany aż do zasięgu globalnego, a zatem każdy emiter zostanie utworzony z takim samym odniesieniem.

Dodanie var self = this rozwiąże problem. Możesz także dodać use strict, aby wychwycić tego rodzaju problemy, ponieważ nie pozwoli Ci zadeklarować zmiennej bez użycia var.

+0

Nie mogę uwierzyć w to, jak głupio mi było tęsknić. Próbowałem naprawić to w czyimś starym kodzie i wyglądało to zbyt głęboko. Całkowicie brakowało braku var przed sobą. Dzięki! – spectorar

Powiązane problemy