Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bluebird Promise Chains: 'Catch' with Result

In order to make this question as useful to as many people as possible, I will exclude my specific implementation details beyond that fact that I am using the Bluebird promise library with Node + Express below.

So, let's say that I have the following chain (where P returns a promise, and res is the Express HTTP response object):

P().then(function(){
    // do nothing if all went well (for now)
    // we only care if there is an error
}).catch(function(error){
    res.status(500).send("An error occurred");
}).then(function(){
    return P();
}).then(function(pVal1){
    return [pVal1, P()];
}) // TODO: catch an error from P() here and log pVal1
.spread(function(pVal1, pVal2){
    if(pVal1 === pVal2) {
        console.log("Success!");
    } else {
        console.log("Failure");
    }
});

Where I have placed the TODO comment above is where I would like to catch an error that might occur from my call to P. If I do catch an error, I would like to log pVal1 and then send a 500 error, as is done in the first catch. However, I am not sure if this is possible with how I am structuring my chain.

I believe that I need to do some "branching," but I do not think that I understand this concept well enough to stop the asynchronous nature of JavaScript from getting the best of me! As such, any help is thoroughly appreciated.

like image 951
nmagerko Avatar asked Jul 12 '15 04:07

nmagerko


People also ask

Does catch return a Promise?

The catch() method returns a Promise and deals with rejected cases only. It behaves the same as calling Promise.

Can you catch a Promise rejection?

If an error condition arises inside a promise, you “reject” the promise by calling the reject() function with an error. To handle a promise rejection, you pass a callback to the catch() function. This is a simple example, so catching the rejection is trivial.

How do you catch a mistake of Promise?

Errors inside the Promises If you throw an error inside the promise, the catch() method will catch it, not the try/catch. In this example, if any error in the promise1, promise2, or promise4, the catch() method will handle it.

How do you wait for results of Promise?

The keyword await is used to wait for a Promise. It can only be used inside an async function. This keyword makes JavaScript wait until that promise settles and returns its result. Here is an example with a promise that resolves in 2 seconds.


2 Answers

Don't forget to catch errors in the end of the chain. That's also the place to send the response.

Catching errors in the middle of a chain is for intermittent error handling; the chain continues to run, so don't send a response just yet.

Here is something to try it out:

// example middleware
function handle(req, res, next) {
    log("----------------");
    return async("p1", "foo").then(function (pVal1) {
        return pVal1;
    }).then(function (pVal1) {
        var p2a = async("p2a", "bar"),
            p2b = async("p2a", "bar").catch(function (error) {
                log("Logging: " + error + " (pVal1 " + pVal1 + ")");
            });
        return [p2a, p2b];
    }).spread(function (pVal1, pVal2) {
        if (pVal1 === pVal2) {
            res.send("Success!");
        } else {
            res.send("Failure");
        }
    }).catch(function (error) {
        res.status(500).send("An error occurred");
        log("Logging: " + error);
    });
}

// ---------------------------------------------------------------------
// mockup response object
var res = {
    status: function (code) {
        log("Sending status: " + code);
        return this;
    },
    send: function () {
        log("Sending response: " + [].join.call(arguments, " "));
        return this;
    }
};

// mockup promise generator
function async(name, value) {
    return new P(function (resolve, reject) {
        if ( confirm("let " + name + " succeed?") ) {
            log(name + " succeeds...");
            resolve(value);
        } else {
            log(name + " fails...");
            reject(name + " has failed");
        }
    });
}

function log() {
     var msg = document.createElement("DIV");
     msg.textContent = [].join.call(arguments, " ");
     document.getElementById("log").appendChild(msg)
     document.body.scrollTop = document.body.scrollHeight;
}
button {
    position: fixed;
    top: 5px;
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/bluebird/2.9.33/bluebird.min.js"></script>

<button onclick="handle(null, res, null)">Go</button>

<div id="log"></div>
like image 105
Tomalak Avatar answered Oct 24 '22 05:10

Tomalak


This is possible if you use the explicit Promise.all instead of returning an array into .spread.

}).then(function(pVal1){
    // this becomes a `Promise.all` - the aggregation is explicit
    var all = Promise.all([pVal1, P()]);
    all.catch(function(e){  // "branching", we both return and `catch` the promise
        console.log("Error, pVal1 is", pVal1);
    });
    return all; // return it
}).spread(function(pVal1, pVal2){
       // ....
});
like image 27
Benjamin Gruenbaum Avatar answered Oct 24 '22 04:10

Benjamin Gruenbaum