cleong
cleong

Reputation: 7606

Bluebird: Waiting for one promise to settle

At the risk of sounding stupid: What's the most efficient way to wait for one promise to settle? Say I have promise A and I want to create promise B. The fulfillment of B does not depend on the final value of A. It should proceed even if A is rejected. The process shouldn't start, however, until A is settled one way or the other.

What I have currently looks like the following:

var prevResult;

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

The code is a bit non-obvious. I'm also a bit worried about chaining a bunch of promises from settle() together, seeing how it's function for performing less trivial kind of coordination. Seems like there ought to be a simpler way of doing this.

Upvotes: 2

Views: 6541

Answers (4)

Benjamin Gruenbaum
Benjamin Gruenbaum

Reputation: 276306

Recently, .reflect was introduced as a more flexible .settle and a better abstraction altogether. Your use case sounds like something that's easy to do with .reflect

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

A full example with your code:

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

Upvotes: 3

Bergi
Bergi

Reputation: 664548

I think the best way would be to put doStuff as both fulfillment and rejection handler:

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

Or alternatively

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

It seems you are trying to queue updateDB operations. I would recommend not to reset prevResult to null, but instead just make it a promise that is fulfilled when all queued operations are done. Have a look at this example.

Upvotes: 0

Roamer-1888
Roamer-1888

Reputation: 19288

Let's assume you have two promise-returning functions doAsync_A and doAsync_B.

The following expression will execute doAsync_A, wait for its promise to settle (to become fulfilled or rejected), then execute doAsync_B

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

doAsync_B will be passed a "PromiseInspection" array (here a single element). If necessary, you can test whether doAsync_A was successful or failed.

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
    }
}

adapted from the bluebird documentation

Upvotes: 0

Jerome Anthony
Jerome Anthony

Reputation: 8021

You can use finally, which fires regardless of the outcome of the previous promise.

Following code is from the 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();
    });
}

Upvotes: 0

Related Questions