结束承诺链

时间:2015-12-05 17:02:28

标签: javascript node.js promise

我遇到了一个关于未终止的Promise链的Promise警告('一个承诺是在一个处理程序中创建的,但是没有从它返回')。我是Promises的新手,怀疑我不应该使用非事件驱动的思维。但我不知道该怎么办。这都在nodejs项目中。

我正在与ZWave服务器交互以打开和关闭灯光。该交互采取以下形式:向控制ZWave网络的服务器发出http请求。我正在使用Promises,因为通过http进行交互的异步性。

在我的程序的一个级别,我定义了以下类方法:

ZWave.prototype.onOff = function (nodeNumber, turnOn) {
var self = this;
var level = turnOn ? 255 : 0;

return new Promise(function (resolve, reject) {
    self.requestAsync(sprintf('/Run/devices[%d].instances[0].commandClasses[0x20].Set(%d)', nodeNumber, level))
    .then(function (value) {
        resolve(value == 'null');
    })
    .catch(function (error) {
        reject(error);
    });
});

};

requestAsync类方法实际上是处理与ZWave服务器交互的方法。从概念上讲,在onOff()中,我试图打开或关闭由this.nodeNumber标识的特定灯光,然后返回该请求的结果。

从Switch类方法调用onOff(),表示特定光,如下所示:

   this.onOff = function( turnOn ) {
    var state = turnOn ? 'ON' : 'OFF';

    var self = this;

    zWave.onOff( this.nodeNumber, turnOn )
    .then( function() {
        winston.info( sprintf( '%s: turned %s', self.displayName, state ) );
        return true;
    } )
    .catch( function( error ) {
        winston.info( sprintf( '%s: error while turning %s => %s', self.displayName, state, error ) );
        return false;
    } );
}

'return true'和'return false'语句是我尝试结束Promise链。但它不起作用,我仍然收到警告。

这让我觉得这是一个更普遍的问题的一个具体例子:你如何从基于Promise的模型转向传统的阻塞代码?

修改

回答评论中的几个问题......

我正在使用蓝鸟。

zWave.onOff()返回一个承诺。

Switch.onOff()和zWave.onOff()是不同类中的不同函数。

所有代码都是javascript。

修改2

我相信我已经实现了jfriend00的建议,虽然我在zWave.onOff()函数中包含了一个.catch()处理程序,但我仍然得到了相同的未处理的promise错误:

ZWave.prototype.onOff = function (nodeNumber, turnOn) {
    var self = this;
    var level = turnOn ? 255 : 0;

    return self.requestAsync( sprintf( '/Run/devices[%d].instances[0].commandClasses[0x20].Set(%d)', nodeNumber, level ) )
        .then( function( value ) {
            resolve( value == 'null' );
        } )
        .catch( function( error ) {
            reject( error );
        } );
};

// function inside Switch class
this.onOff = function( turnOn ) {
    var state = turnOn ? 'ON' : 'OFF';
    var self = this;

    return zWave.onOff( this.nodeNumber, turnOn ).reflect()
        .then( function() {
            winston.info( sprintf( '%s: turned %s', self.displayName, state ) );
            return true;
        } )
       .catch( function( error ) {
            winston.info( sprintf( '%s: error while turning %s => %s', self.displayName, state, error ) );
            return false;
        } );
}

以下是警告的内容:

  

警告:承诺是在处理程序中创建的,但未从中返回       在ZWave.requestAsync(/home/mark/XmasLights/zWaveRequest.js:19:12)       在ZWave.onOff(/home/mark/XmasLights/zWaveRequest.js:93:17)       atOff(/home/mark/XmasLights/switch.js:42:22)       在updateCron(/home/mark/XmasLights/switch.js:80:18)       at dailyUpdate(/home/mark/XmasLights/app.js:196:21)       在/home/mark/XmasLights/app.js:134:58       at processImmediate [as _immediateCallback](timers.js:383:17)

对于警告格式化的运行感到抱歉,我似乎无法通过stackoverflow正确地分隔行。

1 个答案:

答案 0 :(得分:6)

根据Bluebird文档,当您在promise范围内创建promise时会发生此警告,但您不会从该Promise范围返回任何内容。 Bluebird检测到你在promise处理程序中创建了一个promise,但是没有从该处理程序返回任何东西,当它应该链接到其他promise时,它可能是一个未链接的promise。您可以阅读他们对此问题的评论here

在您披露的代码中,您没有显示任何类似Bluebird在其文档中显示的示例,但我猜这里有一个问题:

ZWave.prototype.onOff = function (nodeNumber, turnOn) {
    var self = this;
    var level = turnOn ? 255 : 0;
    return new Promise(function (resolve, reject) {
        self.requestAsync(sprintf('/Run/devices[%d].instances[0].commandClasses[0x20].Set(%d)', nodeNumber, level)).then(function (value) {
            resolve(value == 'null');
        }).catch(function (error) {
            reject(error);
        });
    });
};

你最好避免反模式并做到这一点:

ZWave.prototype.onOff = function (nodeNumber, turnOn) {
    var level = turnOn ? 255 : 0;
    return this.requestAsync(sprintf('/Run/devices[%d].instances[0].commandClasses[0x20].Set(%d)', nodeNumber, level)).then(function (value) {
        return(value == 'null');
    });
};

这里没有必要创建一个新的承诺,因为你已经有一个你可以返回的承诺。您可以阅读有关避免使用here的反模式类型的更多信息。

此外,另一个可能的问题是您创建了一个返回承诺值,但不要从方法this.onOff返回它。您已经明确地从return true;处理程序中完成了return false;.then(),但之后您永远不会对该返回值执行任何操作,因为没有后续的.then()处理程序,承诺本身不会被退回。

this.onOff = function( turnOn ) {
    var state = turnOn ? 'ON' : 'OFF';

    var self = this;

    zWave.onOff( this.nodeNumber, turnOn )
    .then( function() {
        winston.info( sprintf( '%s: turned %s', self.displayName, state ) );
        return true;
    } )
    .catch( function( error ) {
        winston.info( sprintf( '%s: error while turning %s => %s', self.displayName, state, error ) );
        return false;
    } );
}

我建议改变它以返回这样的承诺:

this.onOff = function( turnOn ) {
    var state = turnOn ? 'ON' : 'OFF';

    var self = this;

    // ===== add return statement here
    return zWave.onOff( this.nodeNumber, turnOn )
    .then( function() {
        winston.info( sprintf( '%s: turned %s', self.displayName, state ) );
        return true;
    } )
    .catch( function( error ) {
        winston.info( sprintf( '%s: error while turning %s => %s', self.displayName, state, error ) );
        return false;
    } );
}

然后,向true的来电者提供false.onOff()返回的承诺值。或者,如果您不需要获取这些返回的值,那么您可以删除return truereturn false语句,这样就没有承诺值。

  

这让我觉得这是一个更普遍的问题的具体例子:怎么做   你从一个基于Promise的模型转移到传统的阻塞代码?

您不会为异步操作编写传统的阻止代码。异步操作是异步的,永远不会是传统的阻塞代码。 Promise为管理和协调异步操作提供了更多的结构,但您仍然必须以异步方式为它们编写代码。使用promises编写异步代码会更容易。

JS语言正在添加更多功能,例如生成器和等待,您可以使用它们来帮助解决这个问题。这是关于该主题的简短文章:ES7 async functions