【问题标题】:Ending a Promise chain结束 Promise 链
【发布时间】:2016-03-10 13:26:16
【问题描述】:

我遇到了关于未终止的 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 标识的特定灯,然后返回该请求的结果。

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

   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 的模型转移到传统的阻塞代码?

编辑

回答cmets的几个问题...

我正在使用蓝鸟。

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

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

所有代码都是javascript。

编辑 2

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

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) 在 onOff (/home/mark/XmasLights/switch.js:42:22) 在 updateCron (/home/mark/XmasLights/switch.js:80:18) 在dailyUpdate (/home/mark/XmasLights/app.js:196:21) 在 /home/mark/XmasLights/app.js:134:58 在 processImmediate [as _immediateCallback] (timers.js:383:17)

抱歉,警告的格式化运行,我似乎无法让 stackoverflow 正确分隔行。

【问题讨论】:

  • 您使用的是像qbluebird 这样的Promise 库,还是这些只是普通的节点Promise?可能的答案大相径庭。
  • 能否也添加 requestAsync 方法?
  • @acupajoe:如果他通过var requestFn = bluebird.promisifyAll(require('some module'))导入的话他就不行了
  • 没有从this.onOff返回的Promise? ,例如,return zWave.onOff( this.nodeNumber, turnOn ) ?

标签: javascript node.js promise


【解决方案1】:

根据 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 中返回它。您已经从您的 .then() 处理程序中明确地执行了 return true;return false;,但是您永远不会对该返回值执行任何操作,因为没有后续的 .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;
    } );
}

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

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

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

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

【讨论】:

  • 非常有帮助,谢谢!当我尝试了你的建议后,我会回复。但是有一个问题:第二个建议似乎不涉及对您说我应该更正的代码进行任何更改。我错过了什么?
  • @MarkOlbert - 在我回答的最后一个代码块中,return 前面有一个添加 zWave.onOff() 以返回承诺。
  • 呃!谢谢,我错过了。
猜你喜欢
  • 2019-05-05
  • 2016-02-25
  • 1970-01-01
  • 2019-01-06
  • 2015-11-28
  • 1970-01-01
  • 1970-01-01
  • 2017-04-24
  • 1970-01-01
相关资源
最近更新 更多