【问题标题】:nodejs: inheriting EventEmitternodejs:继承EventEmitter
【发布时间】:2016-04-30 05:03:55
【问题描述】:

我无法创建从 EventEmitter 继承的类。 emit() 函数最终是未定义的。这是问题的简化摘录:

var EventEmitter = require( 'events' );
var util = require( 'util' );
var zWave = require('./zWaveRequest.js');
var CronJobManager = require( 'cron-job-manager' );
var timespanToCron = require( './parseTime.js' ).timespanToCron;
var winston = require( './logger.js' );

const levelCronName = 'level';

var Switch = function (id, displayName, onTime, offTime) {
    var _nodeNum;
    var _nodeName;
    var _lastLevel = -1;
    var _levelPollInterval = config.levelPollInterval;
    var _levelTS = 0;
    var _cronMgr = new CronJobManager( );

    EventEmitter.call( this );

    var self = this;

    function initLevelJob() {
        // the log shows self.emit() doesn't exist (???)
        if( typeof self.emit === 'function' ) winston.info( 'initLevelJob(): self.emit() is defined' );
        else winston.info( 'initLevelJob(): self.emit() is NOT defined' );

        _cronMgr.add( levelCronName, timespanToCron( _levelPollInterval ), function() {
            self.getLevel();
        }, 
        {
            start: true,
        } );
    }

    this.getLevel = function() {
        zWave.curLevel( _nodeNum )
        .then( function( value ) {
            _lastLevel = value;
            _levelTS = Date.now( );

            // this next call always fails with an 'emit is not a function' error
            self.emit( 'level', self.lastLevel, self.lastLevelTS );
        } );
    }

    Object.defineProperties(this, {
        nodeNumber: {
            get: function() { return _nodeNum; },
            set: function( val ) {
                _nodeNum = val;
                initLevelJob( );
            },
        },

        levelPollInterval: {
            get: function() { return _levelPollInterval; },
            set: function( val ) {
                _levelPollInterval = val;
                initLevelJob( );
            }
        },
}

util.inherits( Switch, EventEmitter );

module.exports = Switch;

这里的总体思路是设置一个 cronjob 来 ping 另一台服务器以获取信息(即调用 zWave)。 cronjob 回调更新一些内部变量,然后发出一个事件。

但是 self.emit() 是未定义的,尽管我认为我正在遵循如何从 EventEmitter 继承的示例。

调用代码

从我现在尝试使用 emit() 的角度来看,在 Switch 对象之外什么都没有发生。换句话说,我还没有绑定到 Switch 的任何事件监听器。

以下是我创建 Switch 实例的方式(SunsetSwitch 源自 Switch):

function createSwitch( switchFile ) {
    var raw = JSON.parse( fs.readFileSync( switchFile ) );
    var retVal;

    if( typeof raw.onTime === 'undefined' ) {
        // sunset switch
        retVal = new SunsetSwitch( );

        if( config.forceImmediateOn ) {
            var now = new Date( );

            var sunset = sunCalc.getTimes( now, config.latitude, config.longitude ).sunset;
            retVal.onOffset = Math.ceil( ( now - sunset ) / 60000 ) - 5;

            var turnOff = new Date( now );
            turnOff.setMinutes( now.getMinutes( ) + config.testMode.duration.totalMinutes() );
            retVal.offTime = turnOff;

            retVal.basedOnSunrise = raw.basedOnSunrise;
        }
        else {
            retVal.onOffset = raw.onOffset;
            retVal.offTime = raw.offTime;
            retVal.basedOnSunrise = raw.basedOnSunrise;
        }
    }
    else {
        // regular switch
        retVal = new Switch( );

        retVal.offTime = raw.offTime;
        retVal.onTime = raw.onTime;
    }

    if( config.forceImmediateOn ) retVal.ignoreInitialOff = false;
    else {
        if( typeof raw.ignoreInitial != 'boolean' ) retVal.ignoreInitialOff = true;
        else retVal.ignoreInitialOff = raw.ignoreInitialOff;
    }

    retVal.displayName = raw.displayName;
    retVal.nodeName = raw.nodeName;
    retVal.nodeNumber = raw.nodeNumber;

    return retVal;
}

createSwitch() 从读取一堆 json 文件的文件系统循环中调用:

fs.readdirSync('./switches')
.filter(function (file) {
    return file.substr(-5) === '.json';
})
.forEach(function (file) {
    switches.push(createSwitch('./switches/' + file));
});

这是我目前收到的错误消息:

未处理的拒绝类型错误:self.emit 不是函数 在 /home/mark/XmasLights/switch.js:65:18 在 tryCatcher (/home/mark/XmasLights/node_modules/bluebird/js/release/util.js:11:23) 在 Promise._settlePromiseFromHandler (/home/mark/XmasLights/node_modules/bluebird/js/release/promise.js:488:31) 在 Promise._settlePromise (/home/mark/XmasLights/node_modules/bluebird/js/release/promise.js:545:18) 在 Promise._settlePromise0 (/home/mark/XmasLights/node_modules/bluebird/js/release/promise.js:590:10) 在 Promise._settlePromises (/home/mark/XmasLights/node_modules/bluebird/js/release/promise.js:673:18) 在 Async._drainQueue (/home/mark/XmasLights/node_modules/bluebird/js/release/async.js:125:16) 在 Async._drainQueues (/home/mark/XmasLights/node_modules/bluebird/js/release/async.js:135:10) 在 Immediate.Async.drainQueues [as _onImmediate] (/home/mark/XmasLights/node_modules/bluebird/js/release/async.js:16:14) 在 processImmediate [as _immediateCallback] (timers.js:383:17)

下面是 SunsetSwitch 定义的摘录:

var Switch = require('./switch.js');

var SunsetSwitch = function (id, displayName, onOffset, offTime) {
    Switch.call(this, id, displayName, null, offTime);
}

module.exports = SunsetSwitch;

【问题讨论】:

  • 构造函数内部是否定义了this.emit
  • 你使用的是什么版本的节点?
  • 另外,您在实例化时是使用new Switch() 还是仅使用Switch()
  • 我使用的是 v5.1.0。我正在通过 new Switch() 创建实例,
  • 您的问题可能与您如何使用实例化对象有关,因此我们需要查看该代码。子类化本身(您已显示)看起来不错。

标签: javascript node.js inheritance


【解决方案1】:

感谢所有回复的人,尤其是 jfriend00,他们让我找到了解决方案。

问题源于我在定义 SunsetSwitch 时没有做的事情,它是从 Switch 派生的。

我忽略了在 SunsetSwitch 的模块文件中包含这一行:

util.inherits( SunsetSwitch, Switch );

基于我对 javascript 的有限理解,这一遗漏使 Switch 的原型无法传播到 SunsetSwitch。

我需要记住,在 javascript 中定义继承树并不像在 C# 中那样简单,我在 C# 中的经验最为丰富。您必须同时设置属性 -- Switch.call(this, id, displayName, null, offTime) -- 并复制原型 -- util.inherits(SunsetSwitch, Switch)。

【讨论】:

    猜你喜欢
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多