Using .then() with One or Two Arguments
The .then() method can accept two arguments:
then(onFulfilled, onRejected)
onFulfilled→ called when the promise is resolvedonRejected→ called when the promise is rejected
So far, we mostly used .then() with only one argument, which handles successful cases.
Example: Handling Both Success and Failure
Let’s use our familiar calculateSquare function.
calculateSquare(2)
.then(
value => {
console.log(value);
},
error => {
console.error(error);
}
);
This works correctly:
- If the promise resolves →
onFulfilledruns - If the promise rejects →
onRejectedruns
However, this approach has a limitation.
The Hidden Problem
Let’s introduce an error inside the success handler.
calculateSquare(2)
.then(
value => {
console.log(value);
throw new Error("Something went wrong");
},
error => {
console.error(error);
}
);
Output:
Something went wrong
So far, everything seems fine.
But What Happens If the Error Occurs Later?
Now let’s move the error into the next .then().
calculateSquare(2)
.then(value => {
console.log(value);
return calculateSquare(3);
})
.then(value => {
throw new Error("Something went wrong");
});
Result:
Uncaught (in promise) Error: Something went wrong
Why did this happen?
Because:
- The error occurs inside the second
.then() - There is no error handler attached after it
- The rejection is not caught
This is a common mistake when working with promises.
Fixing the Problem Using .then(undefined, onRejected)
To catch this error, we can add another .then() and pass undefined as the first argument.
calculateSquare(2)
.then(value => {
console.log(value);
return calculateSquare(3);
})
.then(value => {
throw new Error("Something went wrong");
})
.then(
undefined,
error => {
console.error(error.message);
}
);
Now the error is properly handled.
A Better Way: Using .catch()
Because handling errors separately is very common, JavaScript provides a cleaner method called .catch().
The .catch() method is simply a shortcut for:
.then(undefined, onRejected)
Rewriting the Example Using .catch()
calculateSquare(2)
.then(value => {
console.log(value);
return calculateSquare(3);
})
.then(value => {
throw new Error("Something went wrong");
})
.catch(error => {
console.error(error.message);
});
This code behaves exactly the same but is much easier to read.
Returning a Rejected Promise
Instead of throwing an error, we can also return a rejected promise.
calculateSquare(2)
.then(value => {
console.log(value);
return Promise.reject("Something went wrong");
})
.catch(error => {
console.error(error);
});
This has the same effect:
- The promise becomes rejected
- Control moves directly to
.catch()
Important Rule to Remember
A promise becomes rejected in two cases:
- An error is thrown inside a
.then()callback - A rejected promise is returned
In both cases, execution jumps directly to .catch().
Summary
Let’s summarize what we learned:
.then()can take two functions: success and failure handlers.- Errors thrown inside
.then()are converted into rejected promises. - If no error handler exists, the error becomes unhandled.
.catch()is a cleaner and more readable way to handle errors.- Returning a rejected promise behaves the same as throwing an error.
- Error handling should always be placed at the end of a promise chain.
