0

I try to figure out how to proper handle errors in promise chain. There are few promises and one of them throws error. In case of error I would like to terminate function in chain.

The issues I faced with are:

  1. How can we terminate next call from catch block?
  2. How to guarantee execution order then().catch().then() chain? At this moment I observe catch block is called after execution of both then() functions.

Code sample:

function run() {
    test().then(function(data) {
        console.log("w3", "Print data: " + data);
    });
}

function test() {
    return new Promise(function(fulfill, reject) {
        ask()
            .catch(err => console.log("w3", "Process error from ask: " + err))
            .then(reply())
            .catch(err => console.log("w3", "Process error from reply: " + err))
            .then(function(data) {
                console.log("w3", "Finish test");
                fulfill(data);
                // TODO finish data
            })
    });
}

function ask() {
    return new Promise(function(fulfill, reject) {
        console.log("w3", "ask");   
        // fulfill("Hello");
        reject("Cancel Hello");
    });
}

function reply() {
    return new Promise(function(fulfill, reject) {
        console.log("w3", "reply");
        fulfill("World!");
        // reject("Cancel World");
    });
}
Gleichmut
  • 5,953
  • 5
  • 24
  • 32
  • 4
    Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Dec 19 '17 at 03:34
  • 1
    when you add `.catch` that doesn't return a rejected promise or throw an error, you've "handled" the error, therefore the next `.then` will be called ... Promises 101 – Jaromanda X Dec 19 '17 at 03:34
  • 2
    `.then(reply())` ... .then expects a **function** as an argument, you are supplying the result of calling a function ... `.then(reply)` would be what you're after - this too is Promsies 101 – Jaromanda X Dec 19 '17 at 03:35
  • Thanks! I will read about it more right now. Meanwhile, could you please share example how it should done properly? – Gleichmut Dec 19 '17 at 03:35
  • You could try using the second argument of `then`. – Sebastian Simon Dec 19 '17 at 03:37
  • @Gleichmut [Here](https://stackoverflow.com/a/26077868/1048572) [are](https://stackoverflow.com/a/24619782/1048572) [some](https://stackoverflow.com/a/16374031/1048572) [examples](https://stackoverflow.com/q/20714460/1048572) – Bergi Dec 19 '17 at 03:39

2 Answers2

2

That's not how Promise chains work. Promises will only chain correctly if you explicitly return a Promise out of every function invoked in your .then() blocks. If you don't return a Promise out of these functions, the next .then() block is immediately invoked.

You probably want to do something like this:

function run() {
    test()
        .then(function (data) {
            console.log("w3", "Print data: " + data);
        });
}

function test() {
    return ask()
        .then(function (result) {
            return reply();
        })
        .then(function (data) {
            console.log("w3", "Finish test");
            return Promise.resolve(data);
        })
        .catch(function (error) {
            console.log("Hey an error was thrown from somewhere");
            if(error instanceof UnexpectedAskError) {
                //handle specific error logic here. 
            }
        });
}

function ask() {
    console.log("w3", "ask");
    return Promise.reject(new UnexpectedAskError("Ask threw an error"));
}

function reply() {
    console.log("w3", "reply");
    return Promise.resolve("World!");
}

Notice how the ask function returns a specific type of error? You can do something like that if you need to perform different error handling based on which function threw an error.

To specifically answer the questions you asked:

  1. The above method of chaining promises will prevent the next .then() being called if an error is thrown by the previous function.
  2. The above method of chaining will ensure that your .then() blocks are called in the order specified. As long as every .then() is a function, and every function returns a Promise, either through constructing a new Promise(function(resolve, reject)) or through Promise.resolve or Promise.reject, the chain will execute in the correct order.
JamesENL
  • 6,400
  • 6
  • 39
  • 64
1

You just catch at the end of the chain. If there's any error. It will ignore the other then and go direct to catch.

function test() {
    return new Promise(function(fulfill, reject) {
        ask()
            .then(reply())
            .then(function(data) {
                console.log("w3", "Finish test");
                return fulfill(data); // <= Make sure to return here
                // TODO finish data
            })
            .catch(err => console.log("w3", "Process error from reply: " + err))
    });
}

Make sure to return Promise or else it won't catch your error.

fulfill(data); should be return fulfill(data);

Dat Tran
  • 1,576
  • 1
  • 12
  • 16