Skip to main content

then, catch, finally

1. What then() does

javascript
promise.then(onFulfilled, onRejected);

Purpose:

then() registers a handler for the promise's successful outcome - that is, when the promise transitions to the fulfilled state.

How it works:

  • If the promise finished successfully (resolve(value)), the first function onFulfilled(value) is called;
  • If it finished with an error (reject(error)), the second function onRejected(error) is called (optional);
  • It returns a new Promise, allowing you to build chains.

Example:

javascript
new Promise((resolve) => { setTimeout(() => resolve('Success!'), 1000); }) .then((result) => { console.log(result); // Success! return 'Next step'; }) .then((value) => { console.log(value); // Next step });

Every .then() returns a new promise, which can be continued as a chain.

What then() returns

CaseReturnsBehavior
Returning a valuePromise.resolve(value)Passes the result to the next .then()
Returning a promise"unwraps" the promiseWaits until it settles
An error (throw)Promise.reject(error)Goes to .catch()

Example with an error:

javascript
Promise.resolve(10) .then((x) => { throw new Error('Problem!'); }) .catch((err) => console.error(err.message)); // Problem!

2. What catch() does

javascript
promise.catch(onRejected);

Purpose:

catch() catches errors in a promise chain - both from the promise itself and from preceding .then() calls.

How it works:

  • It is called if the promise is rejected;
  • It returns a new promise, allowing the chain to continue.

Example:

javascript
new Promise((_, reject) => { reject('Error'); }) .then(() => console.log('This will not run')) .catch((err) => console.error('Caught:', err)) .then(() => console.log('Continuing on'));

Output:

javascript
Caught: Error Continuing on

After .catch(), the chain continues as if the error had been handled.

Example: catching an error from .then()

javascript
Promise.resolve('OK') .then(() => { throw new Error('Oops!'); }) .catch((err) => console.error('Error caught:', err.message));

.catch() catches all errors up the chain.

3. What finally() does

javascript
promise.finally(onFinally);

Purpose:

finally() runs always, regardless of whether the promise finished successfully (fulfilled) or with an error (rejected).

It is used for cleanup, closing connections, hiding loaders, and so on.

How it works:

  • It does not receive the result (value) or the error (error);
  • It runs after .then() or .catch();
  • It returns a new promise with the same result as the original one.

Example:

javascript
fetch('/data.json') .then((res) => res.json()) .catch(() => console.error('Loading error')) .finally(() => console.log('Loading finished'));

Even if there is an error, finally still runs:

javascript
Loading error Loading finished

Example with a returned value

javascript
Promise.resolve('OK') .finally(() => console.log('Always runs')) .then((value) => console.log(value));

Output:

javascript
Always runs OK

Important:

If you throw an error (throw) inside finally, it replaces the promise's result:

javascript
Promise.resolve('OK') .finally(() => { throw new Error('Error in finally'); }) .then(console.log) .catch((err) => console.error(err.message)); // Error in finally

Summary: comparison

MethodWhen it is calledReceives an argumentReturnsUsed for
then()on resolve (success)the result (value)a new Promisehandling the result
catch()on reject (error)the error (error)a new Promisehandling errors
finally()always (both on success and on error)-a new Promisefinal actions

Analogy

Imagine you ordered a pizza.

  • then() - the courier arrived, the pizza was delivered;
  • catch() - the courier got lost, the order never arrived;
  • finally() - you clean up the box and wash your hands, regardless of whether you got to eat or not.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.