Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

Invoke catch via then (Promises)

How do I invoke the catch callback from within a then callback in case of an error.

3 Answers

Reject

I found a solution on mdn:

Instead of letting .then() return a pending Promise I can return directly a rejected Promise. This seems to be the optimal approach, I could alternatively return an Error:

let promise = new Promise(function (resolve, reject) {
     if (/*everything ok*/) {
          resolve(API_Data);
     } else {
          reject('Error');
     }
});

function resolveFunction(value) {
    let result = doSecondaryWork(value)
    if(result.ok === true) {
         console.log(value);
    }
    else {
           return Promise.reject("There was an error");
            // Throw new Error("There was an error downloading the resource");
     }
}; 

function rejectFunction(value) {
     console.log(value);
}; 

promise
     .then(resolveFunction)
     .catch(rejectFunction); // There was an error
Julian French
Julian French
3,257 Points

Interesting. I wonder why that's the optimal approach. My understanding that the .catch() is there to handle the promise's errors. Correct me if I'm wrong, but it seems like that approach makes the .catch() useless?

Julian French I mean optimal approach because every error which might occur in the chain gets caught by the catch block which serves as an error handler for anything related to the above chain. This makes finding an error easy. In your solution everything would work but I had to push code which might throws / makes errors into the initializer. Maybe there is something even better but this is the most optimal solution.

Julian French
Julian French
3,257 Points

Interesting. I think we're kind of saying the same things here, except you're deciding to handle the promise error inside of the .then(). I just read that the 1st .then() can in fact handle errors, but the example I saw passes in the handling of that into the 2nd parameter, like so:

function resolveFunction(value) {
     console.log(value);
}, function(error) {
     console.log(error);
});

Additionally, check out the code below that I found on the google developers page --> click here. See how the handling of the error is being passed in as a 2nd parameter?

promise.then(function(result) {
  console.log(result); // "Stuff worked!"
}, function(err) {
  console.log(err); // Error: "It broke"
});

Check this out too! (This is all copied and pasted from that same site)

"As we saw earlier, then() takes two arguments, one for success, one for failure (or fulfill and reject, in promises-speak):"

get('story.json').then(function(response) {
  console.log("Success!", response);
}, function(error) {
  console.log("Failed!", error);
})

"You can also use catch():"

get('story.json').then(function(response) {
  console.log("Success!", response);
}).catch(function(error) {
  console.log("Failed!", error);
});

"There's nothing special about catch(), it's just sugar for then(undefined, func), but it's more readable. Note that the two code examples above do not behave the same, the latter is equivalent to:"

get('story.json').then(function(response) {
  console.log("Success!", response);
}).then(undefined, function(error) {
  console.log("Failed!", error);
})

Julian French : Why are last three examples not equal I thought it's just sugar? Can not imagine a case where they are not?!

Julian French
Julian French
3,257 Points

This is answer that the page gives:

The difference is subtle, but extremely useful. Promise rejections skip forward to the next then() with a rejection callback (or catch(), since it's equivalent). With then(func1, func2), func1 or func2 will be called, never both. But with then(func1).catch(func2), both will be called if func1 rejects, as they're separate steps in the chain.

Julian French
Julian French
3,257 Points

I see now. So, you should place the if else logic for the API call inside of the promise. The resolveFunction is used for when the API call returns a successful result. If the result isn't successful (rejected), then you would write the logic on what do for the failure inside of the rejectFunction.

let promise = new Promise(function (resolve, reject) {
    if(result.ok) {
    // You don't have to write === true. Anything inside the parenthesis will evaluate to true unless otherwise specified.
          resolve(API_Data);
     } else {
          reject(Error('There was an error'));
     }
});

function resolveFunction(value) {
    console.log(`Success! Here's your result: ${value}`)
}; 

function rejectFunction(value) {
     console.log(value);
     // The value in this case would be the "Error('There was an error')" from the promise above.
}; 

promise
     .then(resolveFunction)
     .catch(rejectFunction);

But what can I do in the case of a fetch call:

fetch("some+api/v1")
  .then(Response => {
     if(Response.Json() === null) {
        // error
     }
  });
Julian French
Julian French
3,257 Points

Hey Hakim. It'd be useful if you had some example code to work off of. Here's what I would say. You can just chain it to the .then().

let promise = new Promise(function (resolve, reject) {
     if (/*everything ok*/) {
          resolve(API_Data);
     } else {
          reject('Error');
     }
});

function resolveFunction(value) {
     console.log(value);
}; 

function rejectFunction(value) {
     console.log(value);
}; 

promise
     .then(resolveFunction)
     .catch(rejectFunction);

Hi Julian. Here is an simple example where I want to do secondary work inside of the chain. In case of incorrect data, I want to jump immediately to the catch callback.

let promise = new Promise(function (resolve, reject) {
     if (/*everything ok*/) {
          resolve(API_Data);
     } else {
          reject('Error');
     }
});

function resolveFunction(value) {
    let result = doSecondaryWork(value)
    if(result.ok === true) {
         console.log(value);
    }
     // incorrect data or something else
     // handle error via catch
}; 

function rejectFunction(value) {
     console.log(value);
}; 

promise
     .then(resolveFunction)
     .catch(rejectFunction);