1

In case of an error thrown by a promise which is called within parent promise should we catch the error or will it be caught automatically?

Example:

function p1(val)
{
    return new Promise((resolve, reject) => {

        //do something with val
        if(val == true)
           reject(err);

        p2()
        .then(result => resolve(result)
        .catch(reject); //is this line necessary?
    });
}

function p2()
{
    return new Promise((resolve, reject) => {
        //resolve or reject...
    });
}
Dave
  • 2,684
  • 2
  • 21
  • 38
  • If p2 returns a promise, what's the point of the new Promise at all? You should rarely have to use that. – jonrsharpe Apr 22 '19 at 14:17
  • If you actually return p2, which you’re not doing now, then catching can be done at a higher level. E.g. By attaching a catch to p1 – Geert-Jan Apr 22 '19 at 14:18
  • Just do `function p1() { return p2(); }` ? – Jonas Wilms Apr 22 '19 at 14:18
  • I don't think this is *quite* a duplicate of [the construction antipattern question](https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it). It's certainly close, but if you *are* using `new Promise` for some reason, no, the `reject` isn't automatic. – T.J. Crowder Apr 22 '19 at 14:19
  • @Geert-Jan - There aren't any missing returns in the OP's code. – T.J. Crowder Apr 22 '19 at 14:22
  • @Dave - Simplifying for questions is tricky. :-) You want to be sure to simplify *enough*, but also not to simplify *too much*. In this case, removing the fact the call to `p2` might not happen is simplifying too much. Can you edit to make the code a more accurate reflection of what you're doing? Then we can help you better with that specific situation. *(Edit: This was a reply to a comment from Dave that he'd simplified for the question, but in his real code `p2` may or may not need to be called. That's been deleted now for some reason.)* – T.J. Crowder Apr 22 '19 at 14:26
  • 1
    Thank you @T.J.Crowder I will soon update my question – Dave Apr 22 '19 at 14:31
  • Thank you @JonasWilms. I am new to promises and didn't know that it is a well known antipattern. It felt somehow wrong, now I know why. Thanks again. – Dave Apr 22 '19 at 20:23
  • I have updated my question to be more precise on what I tried. I was implementing some logic in p1 before calling the p2 but I guess now I should put that logic in separate promise and chain them. – Dave Apr 22 '19 at 20:55

1 Answers1

2

With your revised code, where you're doing work prior to calling p2, you have a few options. If you're happy for errors in the initial, synchronous part of your functino to be synchronous errors rather than promise rejections, you could just do this:

function p1(val) {
    //do something with val
    if (val == true)
        throw err;

    return p2();
}

The first part of that happens synchronously, then returns the promise from p2. Whether you do this is partially down to what the function is doing and partially down to style. If the initial synchronous part is setting up an asynchronous operation, and you want to have the function throw (rather than return a rejected promise) when it has a problem setting up the asynchronous process (then fulfill/reject based on whether the asynchronous process worked), you might do it like this.

If you want the function to always report success/failure via a promise, then if you're doing initial work, you do need your own promise:

function p1(val) {
    return new Promise((resolve, reject) => {
        //do something with val
        if(val == true)
           reject(err);

        resolve(p2());
    });
}

The resolve(p2()) part resolves the promise p1 created to the promise from p2: If p2's promise rejects, p1's promise rejects with the p2 rejection reason; if p2's promise fulfills, p1's promise fulfills with the p2 fulfillment value.

Or you might use an async function, which has the same result:

async function p1(val) {
    //do something with val
    if(val == true)
        throw err;

    return p2();
}

In both cases, that ensures any error thrown by the initial code prior to p2 results in a rejection rather than a synchronous error, even if the initial code doesn't involve asynchronous processing.

The main thing to remember is that when you already have a promise (such as the one from p2), there's no need to use new Promise; instead, just chain off the promise you already have. (More here.) But when you're doing something before you get the promise, as in your revised example, you might create your own depending on whether you want the first part of your function's errors to be synchronous or promise rejections.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875