skip to Main Content

I was experimenting with this code:

let with999 = Promise.resolve(999);

let returnCatch = with999
.catch(reason => {
  console.log("catch: " + reason);
});

returnCatch.then(data => {
  console.log("then: " + data);
});

when I suddenly realized that:

The promise with999 is fulfilled and therefore the catch() method is not executed, however, the promise returned by catch() (returnCatch in this case) ends up fulfilled with the same value as with999.

So, my question is, why the catch() ends up fulfilled the returnCatch promise?

I expected returnCatch to be pending (because catch() was not executed) and consuming it with then() nothing will happen.

The same happens "doing the opposite", then() rejects a promise:

let rejected = Promise.reject(new Error('Ups!'));

let returnThen = rejected
.then(reason => {
  console.log("then: " + reason);
});

returnThen.
catch(data => {
  console.log("catch: " + data);
});

Can someone explain to me what is going on?

3

Answers


  1. I think you miss understood the behavior of promises.

    A promise is a variable given by an asynchronous function as soon as you call it. When the function is finally executed it will either resolves or rejects the promise.

    If it resolves the promise, the callback passed into the "then" is executed with the parameter filled by the result of the function.

    If it rejects the promise, the callback passed into the "catch" is executed with the paramter filled by the error.

    Specifically in your case, you don’t have an asynchronous function. You are directly resolving or rejecting the promise. Which means, in your first case, you specify that you want the "then" callback to be executed and ignore the "catch". On the second case you are doing the opposite.

    Hope it helps

    Login or Signup to reply.
  2. Why does catch() fulfill the promise that returns?

    "Why" questions are always hard to answer, but it basically boils down to: because it’s useful.

    Maybe this is not immediately obvious from the behaviour of catch() to pass on fulfilment results, but take a look at your second example where .then() passes on the rejection: we want the .catch() callback to executed, to handle any error that did arise earlier in the promise chain. We do not want the promise chain to stop in the middle (with a promise that stays pending) because there was an error and the .then() callback was not getting executed.

    So what is going on?

    You already realised that this behaviour is symmetric between .then(handleResult) and .catch(handleError). But notice that these are actually just simplified syntax for .then(handleResult, null) and .then(null, handleError). The then method actually takes two parameters, one to handle fulfilment and one to handle rejection. You can (and often should) also pass both at once.

    The promise returned by .then() is resolved with the result of the respective handler (or rejected if the call threw an exception), and the idea behind promise chaining is that it always becomes resolved after the original promise got settled. If the respective callback is not provided, by default the result is just passed through – whether that’s .then(null, null), .then(null, handleError) on fulfilled promise, or .then(handleResult, null) on a rejected promise.

    Login or Signup to reply.
  3. The code is the same as chaining .then and .catch to the initial promise. It is not the case that making a new variable for catch requires it to be rejected and then piped to the next then.

    Think of it as just writing the same statement all at one go without multiple variables and the behaviour will make more sense. Since the promise is resolved the first .then will be executed, if the promise was rejected the first .catch would be executed regardless of order or declaring them or how many variables you use to do so.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search