Skip to main content

JavaScript Promises

Promises are the foundation of asynchronous JavaScript. Understanding them deeply is essential for modern web development.

Promise Basics

  • Promises start in a pending state, neither fulfilled or rejected
  • When the operation is completed, a promise will become fulfilled with a value
  • If the operation fails, a promise will get rejected with an error

Creating Promises

The function passed to the Promise constructor will execute synchronously.

From Values

From Async Operations

If you put a fulfilled promise into a fulfilled promise, they will collapse into one.

Handling Promises

Promise.prototype.then()

Promise.prototype.then() accepts two optional arguments (onFulfilled, onRejected):
  • Calls onFulfilled once the promise is fulfilled
  • Calls onRejected if the promise is rejected
  • Passes errors through if onRejected is undefined

Promise.prototype.catch()

Promise.prototype.catch() accepts one argument (onRejected):
  • Behaves like Promise.prototype.then() when onFulfilled is omitted
  • Passes fulfilled values through

Promise.prototype.finally()

Promise.prototype.finally() accepts one argument (onFinally):
  • Calls onFinally with no arguments once any outcome is available
  • Passes through input promise
All three methods will not be executed at least until the next tick, even for promises that already have an outcome.

Combining Promises

Promise.all()

Turns an array of promises into a promise of an array:
If any promise is rejected, Promise.all() will immediately reject with that error.

Promise.race()

Passes through the first settled promise:

Promise.allSettled()

Waits for all promises to settle (fulfilled or rejected):

async/await

The modern way to work with promises.

Basic Usage

Key Points

  • Calling an async function always results in a promise
  • (async () => value)() will resolve to value
  • (async () => throw err)() will reject with an error
  • await waits for a promise to be fulfilled and returns its value
  • await can only be used in async functions
  • await also accepts non-promise values
  • await always waits at least until the next tick before resolving

Practical Example

Running Promises in Series

JavaScript promises are asynchronous, meaning they execute in parallel. To execute promises one after another (sequentially), chain them using Array.prototype.reduce():
Each promise in the chain returns the next promise when resolved, using Promise.prototype.then().

Common Patterns

Timeout with Promise.race()

Retry Logic

Parallel with Limit

Best Practices

Use .catch() or try/catch with async/await to handle errors. Unhandled promise rejections can cause issues.
async/await is more readable and easier to debug. Use .then() for simple chains.
A common mistake is forgetting to await async functions, which returns a promise instead of the value.
When operations don’t depend on each other, run them in parallel with Promise.all() for better performance.