JavaScript Promises Cheat Sheet

Iain Maitland
2 min readNov 25, 2020

Think of a Promise like a container for a value that can only be known at some point in the future (like the result of a network call or reading a file from disk). They exist in one of three states:

  1. pending is the initial state before it has succeeded or failed.
  2. fulfilled when the promise has succeeded.
  3. rejected when the promise has failed.

A Promise has callback functions that are executed when its state changes to handle success or failure. These callbacks can themselves be a Promise allowing for Promise’s to be chained.

A function that returns a promise that fulfills

Calling resolve changes the promises state from pending to fulfilled causing the callback function in foo().then() to execute.

A function that returns a promise that rejects

Calling reject changes the promises state from pending to rejected causing the callback function in foo().catch() to execute.

Chaining promises

The callback function in a .then() can also be a promise. This means promises can be chained like below

Handling Errors

A second callback can be passed to Promise::then to handle the case when the promise rejects.

Using Promise::catch will handle any promise that rejects and is more useful for chaining promises

In reality things are a bit more nuanced so refer to the MDN docs for more detail.

Throwing Errors from inside a Promise

Either call reject with an instance of Error or throw an Error. They both have the same effect

Running code after promises fulfill or reject with .finally()

Promise::finally can be passed a callback that is called once the Promise either fulfills or rejects and the associated callbacks are executed. Think of it like a try...finally.

Gotchas

Calling resolve() and reject() only change a promise’s state — it doesn’t exit the function

You might be surprised at the console output here. It’s because reject doesn't exit the function. It simply sets the promises state to rejected. Walking through what's happening we see that:

  1. foo() is called which returns a new promise with callbacks to handle the promise fulfilling or rejecting
  2. reject('bang') changes the promise's state to rejected but does not exit the function
  3. console.log('I am still called') prints its message to stdout
  4. Now that the function has finished executing the .catch callback is called and prints an error message to stderr

To fix simply return to short circuit the function

A promise’s state can only be set once

You can call resolve() or reject() multiple times but only the first one will actually have any effect (I wish JavaScript would throw an Error or something if you try to fulfill or reject an already fulfilled/rejected promise but oh well…).

--

--

Iain Maitland

Senior software engineer at Skyscanner. I mostly write Java and Python back end systems occasionally foraying in to JavaScript. Also a dad and 49ers fan.