Compile Ready
Module 8 · Asynchronous JavaScript

Introduction to Promises

Intermediate13m read18m practice31m total
PromisesThenCatchMicrotasksChaining

Introduction

A promise is an object representing the eventual result of an asynchronous operation. It starts pending, then settles exactly once as either fulfilled with a value or rejected with a reason.

Promises replaced many callback patterns because they standardize completion, support chaining, and move error propagation into the chain.

Why This Matters

Promises are the foundation under async/await, fetch, modern testing utilities, and almost every JavaScript async abstraction. Interviewers expect you to know not only the states, but also that .then callbacks are microtasks and the promise executor runs synchronously.

Theory

Promise states

A promise has three conceptual states:

  • Pending: the operation has not settled yet.
  • Fulfilled: the operation completed successfully with a value.
  • Rejected: the operation failed with a reason.

Once settled, a promise cannot change state. Calling resolve or reject again has no effect.

Executor versus reactions

The function passed to new Promise(executor) runs immediately and synchronously. The callbacks passed to .then, .catch, and .finally run later as microtasks.

Chaining

.then always returns a new promise. If the handler returns a plain value, the next promise fulfills with that value. If it throws, the next promise rejects. If it returns another promise, the next promise waits for that promise to settle. This is the rule that lets promises flatten async sequences.

Error propagation

A rejection skips fulfillment handlers until a rejection handler is found. A .catch is shorthand for .then(undefined, onRejected). After a catch handles the error and returns normally, the chain becomes fulfilled again.

Promise is eager, not lazy

Creating a promise with new Promise starts the executor immediately. It is not a lazy recipe. If you need laziness, wrap promise creation in a function and call that function later.

Promise limitations

Native promises do not include cancellation by themselves, and they represent one completion, not repeated events. Use AbortController for cancellable Web APIs and events or streams for repeated values.

Visual Diagrams

Promise lifecycle

              resolve(value)
Pending ------------------------> Fulfilled
   |
   | reject(reason)
   v
Rejected

Settled promises do not change state again.

A promise settles exactly once.

Promise chaining

then handler returns value
  -> next promise fulfills with value

then handler throws error
  -> next promise rejects with error

then handler returns promise
  -> next promise adopts that promise's eventual state

Every `.then` returns a new promise, enabling flat composition.

Code Examples

Creating and consuming a promise

The executor starts immediately. The then handler runs as a microtask after the current stack.

Loading…

Error propagation through a chain

Throwing inside a .then rejects the promise returned by that .then.

Loading…

Playground

Loading editor…
Console

Press Run to execute the code and see output here.

Output Prediction

Predict the output #1

javascript
1
2const promise = new Promise(function (resolve) {
3 console.log('executor');
4 resolve('value');
5});
6
7promise.then(function (value) {
8 console.log(value);
9});
10
11console.log('after');

Predict the output #2

javascript
1
2Promise.resolve()
3 .then(function () {
4 console.log('first');
5 return 'second';
6 })
7 .then(function (value) {
8 console.log(value);
9 });
10
11setTimeout(function () {
12 console.log('timer');
13}, 0);
14
15console.log('sync');

Predict the output #3

javascript
1
2Promise.resolve('A')
3 .then(function (value) {
4 console.log(value);
5 throw new Error('boom');
6 })
7 .catch(function () {
8 console.log('caught');
9 })
10 .then(function () {
11 console.log('done');
12 });
13
14console.log('sync');

Coding Exercises

Run promise tasks sequentially

Medium

Implement runSequentially(tasks) where tasks is an array of functions. Each function returns a promise. Run them one after another and return a promise that fulfills with an array of results in order.

Interview Questions

1What are the states of a promise?

A promise starts pending and then settles exactly once as fulfilled with a value or rejected with a reason. After settlement, further attempts to resolve or reject are ignored.

Asked at:GoogleAmazonMeta
2What is the difference between the promise executor and a `.then` callback?

The executor passed to new Promise runs synchronously at construction time. A .then callback is a promise reaction and runs later as a microtask after the current call stack clears.

Follow-ups

  • What happens if a `.then` handler returns a promise?
  • What happens if it throws?

Quiz

1. What does `.then` return?

2. When does the function passed to `new Promise(function (resolve) { ... })` run?

Summary

  • A promise represents one eventual fulfillment or rejection.
  • Promise executors run synchronously; reactions run as microtasks.
  • `.then` returns a new promise and supports flattening by returning another promise.
  • Errors thrown in a chain become rejections and can be handled by `.catch`.

Cheat Sheet

States: pending → fulfilled or rejected; settled once.

Executor: synchronous.

Reactions: .then, .catch, .finally are microtasks.

Chaining: return value → fulfill next; throw → reject next; return promise → adopt it.

Catch: handles rejection and can turn the chain back to fulfilled.