Promises and async/await

Promise

An object used for asynchronous operations. These objects have a state of either pending, fulfilled or rejected. A Promise is created with the Promise() constructor, which takes in a callback function, oftentimes called the executor.
This callback function has two callback functions as parameters:

  • resolve(value): Fulfills the Promise and sets its value.
  • reject(error): Rejects the Promise and sets an error message.

The Promise object has three primary functions:

  • then(fulfilledFn, rejectedFn): Calls fulfilledFn if the Promise is fulfilled and rejectedFn if it is rejected. Returns a new fulfilled Promise with the return value of the callback function.
  • catch(rejectedFn): Calls rejectedFn if the Promise is rejected. Returns a new fulfilled Promise with the return value of the callback function.
  • finally(callback): Calls the callback function whenever the Promise is settled (fulfilled or rejected).

Since these functions all return a new Promise, they can be chained together, such as in this example below:

const errorProm = new Promise((resolve, reject) => {
  reject("There has been a data breach!");
});

errorProm
  .then((val) => console.info(val))
  .catch(err => {
    console.info(`Error: ${err}`);
  })
  .finally(() => console.info('Promise fulfilled'));

The console output will be:

Error: There has been a data breach!
Promise fulfilled

This is because we rejected the Promise, so the then function is skipped and the catch function is executed and then finally, the finally function gets executed.
Did you see what I did there;)

async function

An async function is a function declared with the async keyword, and the await keyword is permitted within it. The async and await keywords enable asynchronous, promise-based behavior to be written in a cleaner style, avoiding the need to explicitly configure promise chains.
In other words, async/await help us write our asynchronous code in a synchronous style.

await

A keyword indicating that JavaScript should wait for a Promise to settle before continuing execution of the code. Traditionally this is only available in async functions, but it can also be used at the top level of modules.

refactor Promise style code with async/await

An API call that returns a Promise will result in a promise chain, and it splits the function into many parts.
Consider the following code:

function getProcessedData(url) {
  return downloadData(url) // returns a promise
    .catch(e => {
      return downloadFallbackData(url)  // returns a promise
    })
    .then(v => {
      return processDataInWorker(v)  // returns a promise
    })
}

This can be rewritten with a single async function as follows:

async function getProcessedData(url) {
  let data;
  try {
    data = await downloadData(url);
  } catch(err) {
    data = await downloadFallbackData(url);
  }
  return processDataInWorker(data);
}

You can also chain the promise with catch():

async function getProcessedData(url) {
  const data = await downloadData(url).catch(err => {
    return downloadFallbackData(url);
  });
  return processDataInWorker(data);
}
Show Comments