0

Today I was just exploring Promises in JavaScript and I came across this:

Promise.reject("Failed");

Gives

Promise { <state>: "rejected", <reason>: "Failed" }
Uncaught (in promise) Failed

Whereas,

Promise.reject("Failed").catch((reason) => console.log(reason));

Gives

Failed
Promise { <state>: "fulfilled", <value>: undefined }

I get the part that in the latter, the rejection is caught and hence just a normal console message but why is the promise itself changed to fulfilled when it was rejected.

Neeraj Kumar
  • 515
  • 7
  • 18
  • 1
    Because it has been: the `catch()` handler literally fulfills the rejected promise, there is now nothing left that "can be done to the promise". – Mike 'Pomax' Kamermans Jul 28 '21 at 16:03
  • It seems unnatural though as the task wasn't "fulfilled" . – Neeraj Kumar Jul 28 '21 at 16:06
  • there's nothing natural about programming languages: a promise is considered "fulfilled" when it has yielded all the data it should yield. When you reject the promise, there's still data left on the table, and it's not done yet. – Mike 'Pomax' Kamermans Jul 28 '21 at 16:08
  • Does this answer your question? [promise with .catch() rejected but appears as fulfilled in Promise.allSetteled](https://stackoverflow.com/questions/61259694/promise-with-catch-rejected-but-appears-as-fulfilled-in-promise-allsetteled) –  Jul 28 '21 at 16:08
  • 1
    @NeerajKumar "*It seems unnatural though*" no, it's mirrors `try { someFn(); } catch (e) { console.log(e); }` - when you have this code, the execution continues after the `try`/`catch` *as if* there was no error. Because you caught and handled it. – VLAZ Jul 28 '21 at 16:14

2 Answers2

1

A call to .catch will return a pending promise.

Whether that pending promise will fulfill depends on:

  1. The promise on which it is called. It that promise fulfils, then the catch promise will just follow suit and resolve to the same outcome without ever executing the callback that was passed as argument.

  2. If the promise on which it is called is rejected (like in your example), then the callback (passed to catch as argument) is executed. This execution determines how the catch-returned promise (that was pending) is resolved. For instance, if the callback throws an error, that promise will actually get in a rejected state.

Demo:

let p = Promise.reject();

let q = p.catch(() => {
    console.log("p rejected");
    // Return a promise that will reject 1 second later
    return new Promise((resolve, reject) => setTimeout(reject, 1000));
});

let r = q.catch(() => {
    console.log("q rejected!");
});
trincot
  • 317,000
  • 35
  • 244
  • 286
  • Can a promise get rejected automatically (without `.reject()`) just like errors can come up without explicitly `throw`ing them? – Neeraj Kumar Jul 29 '21 at 04:35
  • 1
    @NeerajKumar it could be. If there is an error that shows up while a handler is executed (via explicit `throw` or not), that will reject the promise. Also, possible if you use `Promise.all()` and one of the promises is rejected, then the promise returned by `Promise.all` will also be rejected. – VLAZ Jul 29 '21 at 04:47
0

Every Promise.then and Promise.catch returns a fulfilled promise with the value returned from the function handler given to then or catch clause.

Let's take a look at your code.

Promise.reject("Failed").catch((reason) => console.log(reason));

The first Promise.reject("Failed") returns a rejected promise with the value "Failed". The catch clause has an arrow functions. And what is this arrow function returning you may ask? The value returned by console.log which is undefined.

How do you test it you may ask? Simple, paste this in your console.

Promise.reject("Failed").catch((reason) => {
 console.log(reason);
 return "Whoa, what is this?";
});

aaKhan
  • 247
  • 2
  • 16