Promises: a value that's not here yet
The 30-second model
A Promise is a placeholder for a value you'll get later. It has three states:
- pending β the operation is still running.
- fulfilled β done, here's the value.
- rejected β done, here's the error.
Once a Promise settles (fulfilled or rejected), the state is permanent. You can attach handlers any time β past or future.
const p = Promise.resolve(42); // already fulfilled, value 42
const q = Promise.reject(new Error("nope")); // already rejected
p.then(v => console.log("got", v)); // "got 42"
q.catch(e => console.log("err", e.message)); // "err nope".then / .catch / .finally
fetch("/api/user")
.then(r => r.json())
.then(user => console.log(user.name))
.catch(err => console.error("failed:", err))
.finally(() => hideSpinner());.then reads "when the previous step resolved." .catch catches any error from anywhere upstream. .finally runs in both cases β perfect for cleanup that should always happen.
Returning from .then
Whatever you return inside .then becomes the value the next .then receives. If you return another Promise, the chain waits for it. That's how the pipeline works.
In 2026, prefer async/await
This lesson teaches you to recognize and reason about Promises. The next lesson (C4-02) shows the prettier syntax that does the same thing β async/await. You'll use that 95% of the time. But every async/await call is still a Promise underneath, so the model in this lesson is what you're really learning.
Sign up to start coding
Theory is open to everyone. The interactive editor, live preview, and check are unlocked with a 7-day free trial β card required, cancel anytime.
Sign up β free trial βFirst 10 lessons in each track are free. No card needed for those.