JavaScript Promises Cheat Sheet
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:
- pending is the initial state before it has succeeded or failed.
- fulfilled when the promise has succeeded.
- 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:
foo()
is called which returns a new promise with callbacks to handle the promise fulfilling or rejectingreject('bang')
changes the promise's state to rejected but does not exit the functionconsole.log('I am still called')
prints its message to stdout- 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…).