Javascript assíncrono: async/await
Esse é o segundo post da série Javascript Assíncrono, no post passado falamos sobre Promises.
Agora que você já sabe trabalhar com Promises no Javascript, é preciso ir para o próximo nível. Nesse post vamos falar sobre a nova maravilhosa feature do ECMAScript 2017 (ES8) já aprovada e presente nativamente e no Babel.
O async/await é uma nova forma de tratar Promises dentro do nosso código, evitando a criação de cascatas de .then
como vimos no post passado. Vale lembrar que continuamos trabalhando com as Promises, mas elas ficam menos visíveis e verbosas.
Sintaxe
Utilizamos o prefixo async
antes de definir uma função para indicar que estamos tratando de um código assíncrono, e com o prefixo adicionado, podemos utilizar o await
antes das Promises indicando um ponto a ser aguardado pelo código. Vamos entender como isso funciona na prática:
// Modelo antigo (ES6)
function fetchUser(user) {
api.get(`/users/${user}`).then(response => {
console.log(response);
});
}
// Novo modelo (ES8)
async function fetchUser(user) {
const response = await api.get(`/users/${user}`);
console.log(response);
}
Veja como o código ficou mais limpo, não precisamos mais declarar os .then
ou .catch
e ter medo de alguma Promise não executar antes de utilizarmos seu resultado pois o await
faz todo papel de aguardar com que a requisição retorne seu resultado.
Acho que o maior problema que o async/await resolve é a famosa cascata de Promises que falei no post passado. Imaginemos o seguinte código montado com ES6 (sem async/await):
api.get('/users/diego3g').then(user => {
api.get(`/groups/${user.id}`).then(groups => {
groups.map(group => {
api.get(`/group/${group.id}`).then(groupInfo => {
console.log(groupInfo);
});
})
});
});
Esse emaranhado de códigos e .then
que vemos pode ser facilmente melhorado utilizando essa nova sintaxe:
async function fetchUserAndGroups() {
const user = await api.get('/users/diego3g');
const groups = await api.get(`/groups/${user.id}`);
groups.map(group => {
const groupInfo = await api.get(`/group/${group.id}`);
console.log(groupInfo);
});
}
Cada vez que definimos um await
estamos indicando para o nosso código aguardar a Promise seguinte executar e retornar um resultado para seguir adiante, dessa forma evitamos que as próximas linhas executem sem as variáveis necessárias.
Vale lembrar que toda função que definimos com async
automaticamente se torna uma Promise, isto é, podemos anexar funções assíncronas uma às outras dessa forma, vamos ver como isso fica no código:
async function fetchUser() {
const response = await api.get('/users/diego3g');
return response;
}
async function fetchGroups() {
const user = await fetchUser();
const response = await api.get(`/groups/${user.id}`);
console.log(response);
}
E o .catch?
Até agora vimos como enviar o resultado do antigo .then
para nossa variável utilizando o await
, mas como interceptar erros? Com essa nova sintaxe, podemos utilizar o bom e velho try/catch
para garantir que os erros do nosso código e das respostas das Promises não deixem rastros ao usuário final. Vamos ver como funciona essa nova sintaxe:
// Sintaxe antiga (ES6)
function fetchUser() {
api.get('/users/diego3g')
.then(response => console.log(response));
.catch(err => console.log('Erro:', err));
}
// Nova sintaxe (ES8)
async function fetchUser() {
try {
const response = await api.get('/users/diego3g');
console.log(response);
} catch (err) {
console.log('Erro:', err);
}
}
Além de deixar o código mais bonito, uma ótima utilidade é utilizarmos um único catch
para várias Promises, assim, se os erros dessas Promises tiverem o mesmo resultado para o usuário final, podemos tratá-los uma só vez (podendo ainda separar em vários try/catch
caso os erros sejam diferentes).
Quando utilizar?
Uma pergunta difícil de responder, mas na minha opinião, não existe contraindicação para utilizar o async/await, na verdade faz tempo que não escrevo um .then
porque acredito que a nova sintaxe deixa o código muito mais limpo.
Se você trabalha com React ou bibliotecas baseadas em classes pode também adicionar o async
nos métodos da classe:
class Component {
async componentDidMount() {
// ... await api.get(...);
}
}
Concluindo
Com a vinda da nova sintaxe do async/await
no ES8 o código se tornou mais limpo, evitando a necessidade de criar cascatas de .then
e .catch
que estávamos acostumados até então.
Não esquece de deixar suas palmas e um comentário dizendo o que achou do post 🙂