O que é async await em JavaScript?
Introdução
Funções assíncronas usam a sintaxe async
e await
para esperar que uma promise seja resolvida. Para entender melhor este artigo, é recomendado saber como as promises funcionam. Você pode aprender sobre elas aqui.
Callback hell
Uma das razões pelas quais async/await foi introduzido foi para evitar o famoso "callback hell", onde funções eram aninhadas vários níveis de profundidade. Isso acontece muito comumente quando o resultado de uma função requer mais consultas e validações.
Criaremos um fluxo de processo simples para exemplificar um "callback hell":
function suma(a, b, cb) {
cb(a + b); // retorna a soma de dois números em um callback
}
function restar(valor, cantidad, cb) {
cb(valor - cantidad); // subtrai uma certa quantidade de um valor
}
function esMayorACero(valor, cb) {
if (valor > 0) {
cb('Maior que zero');
} else {
cb('Menor que zero');
}
}
const x = 10;
const y = 20;
// se houvesse ainda mais processos derivados, seria aninhado mais e mais
suma(x, y, function (resultado_de_suma) {
// Resultado: 30
restar(resultado_de_suma, 15, function (resultado_de_resta) {
// Resultado: 15
esMayorACero(resultado_de_resta, function (respuesta) {
// Resultado: 'Maior que zero'
console.log(respuesta); // Maior que zero
});
});
});
Este é um exemplo representativo, pois os callbacks são mais comumente usados para processos assíncronos, como solicitações de servidor.
Promises
Para reescrever o exemplo anterior, transformaremos as funções em 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('Maior que zero');
} else {
resolve('Menor que zero');
}
});
}
const x = 10;
const y = 20;
suma(x, y)
.then(function (resultado_de_suma) {
// Resultado: 30
return restar(resultado_de_suma, 15);
})
.then(function (resultado_de_resta) {
// Resultado: 15
return esMayorACero(resultado_de_resta);
})
.then(function (respuesta) {
// Resultado: 'Maior que zero'
console.log(respuesta);
});
Ao retornar uma promise, podemos encadear then()
conforme elas são resolvidas.
Async/Await
Agora vamos reescrever o exemplo usando async/await. Como isso funciona com promises, usaremos as mesmas funções declaradas no código anterior.
Async/Await só funciona dentro de funções assíncronas, ou seja, funções com a sintaxe async function nome_da_funcao() {}
.
const x = 10;
const y = 20;
// função assíncrona com "async"
async function mayorACero() {
try {
let resultado_de_suma = await suma(x, y); // Resultado: 30
let resultado_de_resta = await restar(resultado_de_suma, 15); // Resultado: 15
let respuesta = await esMayorACero(resultado_de_resta); // Resultado: 'Maior que zero'
console.log(respuesta);
} catch (err) {
// tratamento de erros
}
}
mayorACero(); // Resultado: 'Maior que zero'
Se usássemos a sintaxe await
fora de uma função async
, resultaria em um erro.
Graças ao async/await, podemos lidar com funções assíncronas de uma maneira mais sequencial, proporcionando mais clareza ao nosso código.
É recomendado que, ao usar await
, seja feito dentro de um try {} catch() {}
para poder ter controle no catch() {}
das promises que falham. Isso porque, se uma promise falhar dentro do try
, o erro se propagará para o bloco catch
.
Como async/await é relativamente novo, é recomendado usá-lo com cautela, pois não funciona em navegadores mais antigos como o IE11. Você pode ver seu suporte aqui.
Espero que este artigo tenha ajudado você a se familiarizar com alguns dos novos recursos do ECMAScript7, neste caso, async/await.