Why does the following code report an Uncaught (in promise) rejected error when it is being caught?
function Test() {
this.start = function(action) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (action == "fail") return reject("rejected");
resolve("resolved");
}, 1000);
});
}
}
const test = new Test();
const promise = test.start("fail");
promise.then(console.log);
promise.catch(console.error);
The output (in a browser) is:
rejected from the catch()
Uncaught (in promise) rejected from the call to reject
You're forking your promise chain:
promise ---> .then( .. ) ---> ???
\
\
+-> .catch( .. )
The rejection is being caught by the .catch just fine, but it also goes through the .then branch. Both of those branches are resolved independently. And you're not catching the rejection on the .then branch, leading to the uncaught rejection error.
Compare with:
promise.then(console.log).catch(console.error)
Here the chain looks like this:
promise ---> .then( .. ) ---> .catch( .. )
The rejection will skip the .then handler and go to the nearest .catch.
Ok. The answer is obvious, yet easy to miss.
.then(...) returns another promise. So you have to attach the .catch(...) to THAT.
Solution:
const promise = test.start("fail");
promise.then(console.log).catch(console.error);
OR more explicitly:
const promise = test.start("fail");
const promise2 = promise.then(console.log);
promise2.catch(console.error);
@deceze's answer/explaination is pretty good.
Here is the corrected code :
function Test() {
this.start = function(action) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (action == "fail") return reject(new Error("rejected"));
resolve("resolved");
}, 1000);
});
}
}
const test = new Test();
const promise = test.start("fail");
promise.then(console.log).catch(console.error);
you need to chain .then() and .catch() for it to work,
because .then() will return a new promise, and it's that promise that will throw the error you need to catch