Skip to content
Promises
step 1/7

Reading — step 1 of 7

Learn

~3 min readAsync JavaScript

A Promise represents a value that will be available later — or never, if it fails. Network requests, file I/O, timers, database queries — anything asynchronous returns a Promise (or should).

Before Promises, async code looked like nested callbacks ("callback hell"). Promises let you compose async operations linearly, with proper error handling.

Creating a Promise

js

The constructor takes a function with two parameters: resolve and reject. Call exactly ONE of them when your async work finishes.

In practice, you rarely use new Promise directly — you USE Promises returned by APIs (fetch, fs.promises, etc).

The three states

  • pending — the initial state, work not yet finished.
  • fulfilled — completed with a value (resolve(value) was called).
  • rejected — failed with a reason (reject(error) was called).

Once settled (fulfilled OR rejected), a Promise's state is immutable. Calling resolve twice does nothing the second time.

.then() and chaining

.then(onFulfilled, onRejected) registers callbacks for when the Promise settles. The KEY insight: each .then() returns a NEW Promise. That's how you build pipelines.

js

If any step in the chain throws or returns a rejected Promise, control jumps to the nearest .catch(). ONE catch handles errors from the entire chain.

Returning from .then()

What you return from a .then callback determines what the next .then sees:

  • Return a plain value → next .then gets that value.
  • Return a Promise → JavaScript waits for it; next .then gets its resolved value.
  • Throw → chain rejects; next .catch runs.
js

Combinators

js

Use Promise.all for parallel tasks where one failure should fail the whole batch. Use Promise.allSettled when you want every result regardless.

Microtasks — the hidden detail

Promise callbacks run in the microtask queue, processed after the current synchronous code but before macrotasks (setTimeout):

js

Microtasks > macrotasks > pending I/O. Knowing this matters for tests and ordering-sensitive code.

Common mistakes

  • Forgetting to return a Promise inside .then — chain breaks, next .then gets undefined.
  • .catch only at the end of one chain — won't catch errors from a SIBLING chain.
  • Not handling rejection — uncaught Promise rejections cause warnings (and crash in newer Node).
  • Calling resolve twice — silent no-op the second time. State is locked after first settle.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…