2

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.

cleong
  • 7,242
  • 4
  • 31
  • 40
  • You mean you want to have two promises and even if Promise A is rejected, you ll ignore it and want to proceed? – thefourtheye Apr 19 '15 at 09:25
  • @thefourtheye. Yes. The operations that generate A and B are independent. They just can't happen concurrently. – cleong Apr 19 '15 at 09:48
  • Yes, your code is very non-obvious, especially that `prevResult = null` thing. What exactly is this for? What is `doStuff`? – Bergi Apr 19 '15 at 12:44
  • Setting `prevResult` to null allow the next operation to proceed. I guess the code would be a bit more obvious if I make the condition `prevResult && !prevResult.isFulfilled())` and remove the finally(). That'd mean the fulfillment value doesn't get gc'ed though. – cleong Apr 20 '15 at 10:06

4 Answers4

3

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;
}
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
0

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();
    });
}
Jerome Anthony
  • 7,823
  • 2
  • 40
  • 31
  • 1
    finally() returns a promise that yields the value of the promise on which it's called (and not the return value of the callback). – cleong Apr 19 '15 at 09:51
0

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

Roamer-1888
  • 19,138
  • 5
  • 33
  • 44
0

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.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Why the anonymous wrappers? Why not just `.then(doStuff, doStuff)`? – jfriend00 Apr 19 '15 at 15:24
  • @jfriend00: Depends on whether you want any arguments to `doStuff` or not. If you don't care, then `.then(doStuff, doStuff)` is certainly better. – Bergi Apr 19 '15 at 15:41