3

How do we deal with errors that happen in the then function of a promise?

getLocationId(lat, lon, callback)
{
    let self = this;

    return this._geocoder.reverse({lat: lat, lon: lon})
        .then(this._parse)
        .catch(function(err) {
            callback(err);
        });
}

_parse(res)
{
    if (res.length < 1)
        throw new Error('No results from Maps API');

    let value = res[0].administrativeLevels;

    if (!value || value.length < 1) {
        throw new Error('No administrative levels available');
    }

    if ('level2long' in value)
        return value.level2long;
    if ('level1long' in value)
        return value.level1long;

    throw new Error('No suitable location found');
}

For instance, how do I deal with this._parse throwing an error? I thought the catch function of the promise only deals with the reject handler. Does it also deal with errors thrown in the then?

mrQWERTY
  • 4,039
  • 13
  • 43
  • 91
  • 1
    O.T. but related: It is unnecessary to pass `callback`. Instead of `getLocationId(lat, lon, errorHandler)`, exactly the same effect is achieved with `getLocationId(lat, lon).catch(errorHandler)`. – Roamer-1888 Aug 01 '16 at 08:33
  • This surprised me as well. I would want the `.catch()` (call it whatever you like) to only respond to Promise failure. – Andrew Oct 22 '19 at 17:10

1 Answers1

5

An exception thrown in any .then() handler will automatically be caught by the promise infrastructure and will turn the current promise chain into a rejected promise. The chain will then jump to the next .catch() handler where the exception will be the error reject reason.

Here's an example:

Promise.resolve().then(function() {
    throw "foo";
}).then(function() {
     console.log("in 2nd .then() handler");     // will not get here
}).catch(function(err) {
    console.log(err);                           // will show "foo"
});
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Great. Now what if you don't want this behavior? What if you want the error to somehow propagate outside of the Promise code? (But you still want to catch an error in the Promise itself.) – Andrew Oct 22 '19 at 17:11
  • 2
    @Andrew - Well, you can't turn an asynchronous exception into a synchronous exception that's caught with a normal synchronous `try/catch`. So, it HAS to be handled via the promise infrastructure once it's inside a promise handler. You don't have to handle it locally. You can let it propagate up the promise chain and handle it in some level of caller above, but a `.catch()` or the equivalent when using `async/await` has to catch it somewhere. – jfriend00 Oct 22 '19 at 17:41
  • 1
    @Andrew - Keep in mind an exception that occurs inside a `.then()` handler is asynchronous. Whatever synchronous code called this has ALREADY returned and is no longer active. So, that's why you can't catch it synchronously. – jfriend00 Oct 22 '19 at 17:42
  • True. So if I don't control or don't know about potential errors, how would I be able to distinguish Promise errors vs. errors in the `.then()` code then? – Andrew Oct 22 '19 at 17:46
  • @Andrew - You catch them the same place. They will just be different exceptions. No different than using `try/catch` with synchronous code where a coding error and a program condition that throws an exception both throw exceptions, just different exceptions. – jfriend00 Oct 22 '19 at 17:50
  • Well it is different though, and that's exactly my problem: if the Promise fails, I want to show one kind of error; if the `.then()` code fails, I want to handle it in a different way. If I don't know what kinds of errors are going to be coming through, then I need a way to distinguish them. I suppose I could `try/catch` inside the `.then()`, and then throw my own error, or something like that... – Andrew Oct 22 '19 at 17:52
  • Aha! This is what I was looking for, and it's on a question that you answered :O https://stackoverflow.com/a/47150921/1599699 (Answer: `.catch()` first, then `.then()`.) – Andrew Oct 22 '19 at 17:58