蓝鸟:等待一个承诺来解决

Bluebird: Waiting for one promise to settle

冒着听起来很愚蠢的风险:等待一个 promise 结算的最有效方法是什么?假设我有承诺 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;
}

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

您可以使用 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();
    });
}

假设您有两个承诺返回函数 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

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

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

或者

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

您似乎正在尝试对 updateDB 操作进行排队。我建议不要将 prevResult 重置为 null,而只是让它成为所有排队操作完成后履行的承诺。看看 this example.

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

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

您的代码的完整示例:

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