Skip to content

What is async await in JavaScript?

Introduction

Async functions use the async and await syntax to wait for a promise to be resolved. To better understand this article, it is recommended to know how promises work. You can learn about them here.

Callback hell

One of the reasons async/await was introduced was to avoid the well-known "callback hell" where functions were nested several levels deep. This happens very commonly when the result of a function requires further queries and validations.

We will create a simple process flow to exemplify a "callback hell":

javascript
function suma(a, b, cb) {
  cb(a + b); // returns the sum of two numbers in a callback
}
function restar(valor, cantidad, cb) {
  cb(valor - cantidad); // subtracts a certain amount from a value
}
function esMayorACero(valor, cb) {
  if (valor > 0) {
    cb('Mayor a cero');
  } else {
    cb('Menor a cero');
  }
}

const x = 10;
const y = 20;
// if there were even more derived processes, it would be nested more and more
suma(x, y, function (resultado_de_suma) {
  // Result: 30 
  restar(resultado_de_suma, 15, function (resultado_de_resta) {
    // Result: 15
    esMayorACero(resultado_de_resta, function (respuesta) {
      // Result: 'Mayor a cero'
      console.log(respuesta); // Mayor a cero
    });
  });
});

This is a representative example since callbacks are most commonly used for asynchronous processes such as server requests.

Promises

To rewrite the previous example, we will transform the functions into promises:

javascript
function suma(a, b) {
  return new Promise(function (resolve, reject) {
    resolve(a + b);
  });
}
function restar(valor, cantidad) {
  return new Promise(function (resolve, reject) {
    resolve(valor - cantidad);
  });
}
function esMayorACero(valor) {
  return new Promise(function (resolve, reject) {
    if (valor > 0) {
      resolve('Mayor a cero');
    } else {
      resolve('Menor a cero');
    }
  });
}

const x = 10;
const y = 20;

suma(x, y)
  .then(function (resultado_de_suma) {
    // Result: 30
    return restar(resultado_de_suma, 15);
  })
  .then(function (resultado_de_resta) {
    // Result: 15 
    return esMayorACero(resultado_de_resta);
  })
  .then(function (respuesta) {
    // Result: 'Mayor a cero'
    console.log(respuesta);
  });

By returning a promise, we can chain then() as they are resolved.

Async/Await

Now we will rewrite the example using async/await. Since this works with promises, we will use the same functions declared in the previous code.

Async/Await only works inside asynchronous functions, that is, functions with the syntax async function function_name () {}.

javascript
const x = 10;
const y = 20;

// asynchronous function with "async"
async function mayorACero() {
  try {
    let resultado_de_suma = await suma(x, y); // Result: 30
    let resultado_de_resta = await restar(resultado_de_suma, 15); // Result: 15
    let respuesta = await esMayorACero(resultado_de_resta); // Result: 'Mayor a cero'
    console.log(respuesta);
  } catch (err) {
    // error handling
  }
}

mayorACero(); // Result: 'Mayor a cero'

If we used the await syntax outside of an async function it would result in an error.

Thanks to async/await we can handle asynchronous functions in a more sequential way, providing more clarity to our code.

It is recommended that when using await it is done inside a try {} catch() {} to be able to have control in the catch() {} of the promises that fail. This is because if a promise fails within the try, the error will propagate to the catch block.

Because async/await is relatively new, it is recommended to use it with caution as it does not work in older browsers like IE11. You can see its support here.

I hope this article has helped you become familiar with some of the new features in ECMAScript7, in this case, async/await.