【问题标题】:Bluebird: Waiting for one promise to settle蓝鸟:等待一个承诺解决
【发布时间】:2015-06-26 00:08:50
【问题描述】:

冒着听起来很愚蠢的风险:等待一个承诺达成的最有效方法是什么?假设我有承诺 A,我想创建承诺 B。B 的实现不取决于 A 的最终值。即使 A 被拒绝,它也应该继续。然而,在 A 以一种或另一种方式解决之前,该过程不应开始。

我目前的样子如下:

var prevResult;

function doStuff() {
    if (prevResult) {
        prevResult = promise.settle([ prevResult ]).then(function() {
            return doStuff();
        })
    } else {
        prevResult = updateDB().finally(function() {
            prevResult = null;
        });
    }
    return prevResult;
}

代码有点不明显。我也有点担心将来自结算()的一堆承诺链接在一起,看看它是如何执行不那么琐碎的协调的功能。似乎应该有一种更简单的方法来做到这一点。

【问题讨论】:

  • 你的意思是你想要有两个promise,即使Promise A被拒绝,你也会忽略它并想继续?
  • @thefourtheye。是的。生成 A 和 B 的操作是独立的。它们只是不能同时发生。
  • 是的,您的代码非常不明显,尤其是 prevResult = null 的东西。这究竟是为了什么? doStuff 是什么?
  • prevResult 设置为 null 允许进行下一个操作。我想如果我将条件设为prevResult && !prevResult.isFulfilled()) 并删除finally(),代码会更明显一些。这意味着履行价值不会得到 gc'ed。

标签: node.js promise bluebird


【解决方案1】:

您可以使用 finally,无论前一个承诺的结果如何,它都会触发。

以下代码来自 bluebird github doco。

function ajaxGetAsync(url) {
    return new Promise(function (resolve, reject) {
        var xhr = new XMLHttpRequest;
        xhr.addEventListener("error", reject);
        xhr.addEventListener("load", resolve);
        xhr.open("GET", url);
        xhr.send(null);
    }).finally(function() {
        $("#ajax-loader-animation").hide();
    });
}

【讨论】:

  • finally() 返回一个 Promise,该 Promise 产生调用它的 Promise 的值(而不是回调的返回值)。
【解决方案2】:

假设您有两个返回承诺的函数 doAsync_AdoAsync_B

下面的表达式会执行doAsync_A,等待它的promise解决(被实现或被拒绝),然后执行doAsync_B

Promise.settle([doAsync_A()]).then(doAsync_B);

doAsync_B 将传递一个“PromiseInspection”数组(这里是单个元素)。如有必要,您可以测试doAsync_A是成功还是失败。

function doAsync_B(results) {
    var r = results[0];
    if (r.isFulfilled()) {  // check if was successful
        console.log(r.value()); // the promise's return value
    } else if (r.isRejected()) { // check if the read failed
        console.log(r.reason()); // the promise's rejection reason
    }
}

改编自bluebird documentation

【讨论】:

    【解决方案3】:

    我认为最好的方法是将doStuff 同时作为履行和拒绝处理程序:

    prevResult = prevResult.then(function() { return doStuff(); },
                                 function() { return doStuff(); });
    

    或者

    prevResult = prevResult.catch(ignore).then(function() { return doStuff(); });
    

    您似乎正在尝试对updateDB 操作进行排队。我建议不要将prevResult 重置为null,而是将其作为一个承诺,当所有排队的操作都完成后就可以实现。看看this example

    【讨论】:

    • 为什么是匿名包装器?为什么不只是.then(doStuff, doStuff)
    • @jfriend00:取决于您是否想要doStuff 的任何参数。如果你不在乎,那么.then(doStuff, doStuff) 肯定更好。
    【解决方案4】:

    最近,.reflect 被引入为更灵活的.settle 和更好的抽象。您的用例听起来很容易使用 .reflect

    A.reflect().then(function(){
       return doSomethingThatReturnsB();
    });
    

    您的代码的完整示例:

    var prevResult;
    function doStuff() {
        prevResult = Promise.resolve(prevResult).reflect().then(function(){
            return updateDB();
        });
        return prevResult;
    }
    

    【讨论】:

    • .reflect 似乎获得了一些动力。我会发现 .inspectify 更直观。
    • 你知道我
    • “反射”的问题在于它是比喻性的。从字面上看,反射是镜子中发生的事情,或者modelled mathematically。我唯一能记住 Petkaantonov 用法的方法是"reflect" == "inspectify" :D
    • 感谢您的回答。我不认为第二个例子是正确的。
    猜你喜欢
    • 2018-10-02
    • 1970-01-01
    • 2018-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-29
    • 1970-01-01
    • 2018-03-30
    相关资源
    最近更新 更多