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":
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:
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 () {}
.
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.