Andrew's Digital Garden

Promises

A promise is in one of three states: pending, fulfilled, or rejected. A promise has two 'fates': resolved or unresolved. A promise is settled if it's either fulfilled or rejected.

Creating a promise

new Promise((resolve, reject) => { someAsynchronousWork((result, error) => { if (error) { // This will call .catch reject(error); return; } // This will call .then resolve(result); }); });

Chaining

Promises are chained with .catch, .then, and .finally. Each of these return its own promise, which can then subsequently be chained.

.then does accept two arguments, onFulfilled and onRejected. It's called when a promise is resolved.

prom1.then(successCallback).catch(failureCallback); /* very similar to prom1.then(successCallback, failureCallback); */

A .catch is essentially a .then, without the onFulfilled argument. It's called when a promise is rejected.

.catch should always be used somewhere in the chain to handle errors. As this also returns a promise, it's possible to .then a .catch block. If you want to skip from one .catch to another, avoiding any .thens in between, you can re-throw an error. Not having any .catch chain will mean you have to deal with Unhandled promise rejection errors.

.finally will always run once the promise is settled, regardless of it being fulfilled or rejected. This is handy for cleanup and other tasks which you want to always run.

Promise methods

Promise.resolve and Promise.reject both exist to return a resolved and rejected promise with a value, respectively.

Returning

The next link in the chain will receive the return value of the previous, as each return their own promise with data inside. If you want to pass data from one .then to another, make sure to return the value explicitly, not just use it.

doSomething() .then(function (result) { // This has to be returned for `doThirdThing` to have `newResult` return doSomethingElse(result); }) .then(function (newResult) { return doThirdThing(newResult); }) .then(function (finalResult) { console.log(`Got the final result: ${finalResult}`); }) .catch(failureCallback);

.then anti-pattern

It's generally better to use a .then with a .catch to handle resolved and rejected promises respectively, as it's easier to parse than two argument .thens. It also allows you to have one area to catch all errors, regardless of which handler prompted them. When using only a .then, if the onFulfilled function errors, it won't be caught by the onRejected in the same .then.

Async/Await

These are syntactic sugar for promises, and mainly exist to make code more readable. As soon as async is added to a function, it will always return a Promise. Note that using the async keyword doesn't magically make things happen off the main thread. Async functions can still block the main thread if they're not actually async.

async function addNums(a, b) { return a + b; } // Is the same as... function addNums(a, b) { return new Promise((resolve) => { resolve(a + b); }); }
// This code... async function pingEndpoint(endpoint) { const response = await fetch(endpoint); return response.status; } // ...is equivalent to this: function pingEndpoint(endpoint) { return fetch(endpoint) .then((response) => { return response.status; }); }

https://www.joshwcomeau.com/javascript/promises/ https://github.com/domenic/promises-unwrapping/blob/master/docs/states-and-fates.md

[[20210927102602-js-event-loop]]

[[js]]

Promises