then, catch, and finally
A Promise by itself does not do anything useful — you need to tell it what to do when it settles. The three methods for this are .then(), .catch(), and .finally().
.then()
Section titled “.then()”.then(onFulfilled) registers a callback that runs when the Promise fulfills. The callback receives the resolved value:
const promise = new Promise(resolve => { setTimeout(() => resolve(42), 500);});
promise.then(value => { console.log(value); // 42 — runs 500ms later});.then() returns a new Promise, making it chainable. The value returned from the .then callback becomes the resolved value of the next Promise in the chain:
promise .then(value => value * 2) // 84 .then(value => value + 1) // 85 .then(value => console.log(value)); // 85Each .then transforms the value and passes it to the next.
.catch()
Section titled “.catch()”.catch(onRejected) registers a callback that runs when the Promise rejects. It is shorthand for .then(null, onRejected):
const badPromise = new Promise((resolve, reject) => { reject(new Error('Something went wrong'));});
badPromise .then(value => console.log('Success:', value)) .catch(error => console.error('Error:', error.message));// Error: Something went wrong.catch() placed at the end of a chain catches any rejection that propagated up the chain — from the original Promise or from any .then callback that threw:
fetch('https://invalid-url-that-does-not-exist.example') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Request failed:', error.message));If the fetch fails, or if response.json() throws, .catch handles it.
.finally()
Section titled “.finally()”.finally(callback) runs after the Promise settles, regardless of whether it fulfilled or rejected. Use it for cleanup that must happen either way:
showLoadingSpinner();
fetch('https://open.er-api.com/v6/latest/USD') .then(response => response.json()) .then(data => displayRates(data.rates)) .catch(error => showErrorMessage(error.message)) .finally(() => hideLoadingSpinner());The spinner hides whether the request succeeded or failed. .finally does not receive the value or error — it just runs.
The chain pattern for fetch
Section titled “The chain pattern for fetch”The standard Promise chain for a fetch call has three steps:
fetch(url) .then(response => { if (!response.ok) throw new Error(`HTTP ${response.status}`); return response.json(); }) .then(data => { // use data here }) .catch(error => { // handle error here });Note the first .then: it checks response.ok before calling .json(). fetch only rejects on network failure — a 404 or 500 response is still a “fulfilled” Promise. You have to check response.ok yourself and throw to propagate it as an error.
Return values in then
Section titled “Return values in then”What you return from .then matters:
- Return a plain value → next
.thenreceives it - Return a Promise → next
.thenwaits for that Promise to resolve - Throw an error → execution jumps to the next
.catch
fetch(url) .then(response => response.json()) // returns a Promise — chain waits for it .then(data => data.rates) // returns a plain value .then(rates => console.log(rates)); // receives the rates objectExercise
Section titled “Exercise”- Create a Promise that resolves to
'BudgetBuddy'after 1 second. Use.thento log the value. - Create a Promise that rejects with
new Error('No data'). Chain a.catchto log the error message. - Using the real ExchangeRate-API (
https://open.er-api.com/v6/latest/USD), write afetchchain that:- Checks
response.okand throws if false - Parses the JSON
- Logs the
rates.EURvalue - Catches any error and logs it
- Checks
- Add
.finallyto the chain from step 3 that logs'Request complete'regardless of outcome.
.then(fn)runsfnwhen the Promise fulfills; returns a new Promise with the callback’s return value..catch(fn)runsfnwhen the Promise rejects — handles errors anywhere in the chain..finally(fn)runsfnafter the Promise settles — good for cleanup like hiding spinners.fetchonly rejects on network failure; checkresponse.okmanually for HTTP errors.- Return a Promise from
.thento wait for it; throw an error to jump to.catch.