Angular Async/Await: Por que você precisava dele e como usá-lo
O que é Async Await em Angular e como usá-lo para evitar o inferno de retorno de chamada? Aprenda as respostas em nosso artigo mais recente
Angular é uma ótima estrutura, mas escrever código assíncrono e fazer chamadas assíncronas é difícil. Especialmente se você não conseguir decidir entre Async/Await e Angular Promise. Portanto, neste tutorial, vou ajudá-lo a entender as diferenças entre Async/Await e Promise por meio de exemplos e trechos de código. Também explicarei como você pode facilmente evitar o inferno de retorno de chamada e demonstrarei como usar Async/Await em JavaScript com a ajuda de Ignite UI for Angular Components.
O que é código assíncrono no Angular?
Quando falamos de código assíncrono, queremos dizer simplesmente que o código não é executado sequencialmente e o processo envolve multithreading. É uma forma de programação paralela que executa um bloco de código separado sem quebrar o thread principal do aplicativo. A execução de código assíncrono é útil no caso de grandes iterações ou quando você tem operações complexas.
Mas se você busca simplicidade e operações de curta duração para seu aplicativo Angular, é melhor evitar a programação assíncrona. Normalmente, o código assíncrono é mais difícil de ler, portanto, qualquer coisa que possa melhorar sua legibilidade e torná-lo mais simples para os desenvolvedores é considerada um impulsionador da qualidade. E o JavaScript tem seus próprios truques e mecanismos para lidar com isso.
How JavaScript Handles Asynchronous Code
Por padrão, o JavaScript é uma linguagem síncrona de thread único, executando uma instrução por vez, de cima para baixo. Isso significa que novos threads e processos não podem executar código em paralelo ao fluxo principal do programa. Ele tem uma pilha de chamadas e uma memória heap e executa o código em ordem e deve terminar de executar um pedaço de código antes de passar para o próximo. Tudo acontece sequencialmente. Mas o que acontece quando, por exemplo, você deve fazer várias chamadas AJAX em uma única página?
A primeira solução que vem à mente é o uso de retornos de chamada. Mas eles levam a um grande problema conhecido pelos programadores como "inferno de retorno de chamada". Essencialmente, essa é uma estrutura de código aninhada e promissora que requer a realização de várias solicitações e transformações de dados, muitas vezes resultando em código difícil de manter e ler e um aplicativo menos escalonável.
Acontece que os retornos de chamada não são a melhor maneira de lidar com o código assíncrono para seu aplicativo Angular. E então? Talvez Angular promessa? Esse padrão encapsula com eficiência as operações assíncronas e notifica quando elas são concluídas. No entanto, embora forneça um código mais limpo e de fácil manutenção, usar Angular Promise não é a solução ideal, pois, muitas vezes, ele reutiliza o mesmo código repetidamente, contradizendo o principle.cl DRY (Don't Repeat Yourself)
Felizmente, temos Async/Await em Angular.
Using Async/Await in Angular
Uma das melhores melhorias em JavaScript é o recurso Async/Await introduzido no ECMAScript 7. Basicamente, Async/Await funciona em cima do Promise e permite que você escreva código assíncrono de maneira síncrona. Ele simplifica o código e torna o fluxo e a lógica mais compreensíveis.
Observe que, como ele não usa mais o encadeamento then e catch, você pode lidar com erros executando try/catch.
Async/Await vs Promise: Qual é a diferença?
Para apresentar as diferenças entre Async/Await e promises, vamos fazer uma tabela para compará-las de uma forma mais digerível e concisa.
Promise |
Async/Await |
Promise é uma operação que tem a garantia de concluir sua execução em algum momento no futuro |
Async/Await é construído com base em promessas. Eles são açúcar sintático para promessas, fazendo com que o código pareça mais síncrono |
O tratamento de erros é feito usando os métodos .then() e catch() |
O tratamento de erros é feito usando os métodos try() e catch() |
Às vezes, pode ser difícil entender as cadeias de promessas |
Async e await facilitam a leitura e a compreensão do fluxo do programa no código |
Tem 3 estados – pendentes, resolvidos e rejeitados |
Ele retorna uma promessa resolvida ou rejeitada |
Vamos criar um exemplo com ambas as sintaxes em uma Angular Grade de Dados e ver as diferenças. Temos uma função que está fazendo duas chamadas assíncronas para uma API, uma para obter dados do usuário e outra para obter clubes nos quais os usuários são membros. A segunda chamada depende da primeira, o que significa que getUserData() deve ser concluída antes de prosseguir com a outra solicitação. Ambas as sintaxes são fáceis de ler, mas é claro que usar promessas com .then() e .catch() pode levar ao inferno de retorno de chamada, o que torna o código difícil de entender e manter.
const makeRequest = () => getUserData() . then(user => getClubsForUser(user.id)) .then(console.log) .catch(err => console.log('Error: ' + err.message));
const makeRequest = async () => { try { let user = await getUserData(); let clubs = await getClubsForUser(user.id); console.log(clubs); } catch(err) { console.log(err.message); } };
Como usar o Async/Await no Angular com Ignite UI
Vamos criar uma função que obterá dados do usuário de uma entrada de formulário e, em seguida, fará uma solicitação a uma API para verificar se as credenciais do usuário estão corretas e, em caso afirmativo, redirecionará para a página inicial. Usar Async/Await no Ignite UI for Angular pode nos ajudar nessa situação. Temos uma solicitação para uma API que é uma operação assíncrona e é por isso que usaremos await para ela e, se não houver outros problemas, salvaremos os dados.
const submitLoginData = async () => { try { if (this.userInput.email && this.userInput.password) { const response = await this.loginUser(this.userInput); if (response.statusCode === 200) { alert('User is successfully logged in!'); await saveUserData(response.data); this.router.navigate(['/']); } else { alert(response.message); this.router.navigate(['/login']); } } } .catch(err) { alert('Something went wrong, try again later!') this.router.navigate(['/login']); } }
Definitivamente, podemos usar .then() e .catch() aqui, mas Async/Await em Ignite UI for Angular torna o código mais elegante. Cabe à pessoa que está escrevendo o código escolher qual sintaxe usar. Mas também, é recomendável aderir a uma abordagem, pois misturar estilos pode tornar o código complicado.
Async/Await Angular Best Practices
Quando estamos usando async e await para lidar com código assíncrono, devemos sempre colocar nosso código no bloco try/catch. Dessa forma, garantiremos que, mesmo que a promessa esteja gerando um erro, ela será detectada e processada corretamente.
async function loadComponents() { try { this.components = await fetchComponentsByType('charts'); } .catch(err) { logger.error(err); } }
Com Ignite UI, não precisamos retornar explicitamente uma promessa em uma função assíncrona. Na verdade, uma função assíncrona sempre retorna uma Promise. O que significa que a criação de uma Promise dentro de uma função assíncrona apenas adiciona sobrecarga de desempenho ao nosso aplicativo Angular.
async function loadChartSelectors() { return Promise.resolve(['igx-data-chart', 'igx-pie-chart', 'igx-category-chart']); }
Resumo
As palavras-chave Async/Await facilitam a leitura e a depuração do código. No entanto, se quisermos usá-los corretamente, devemos entender como as promessas funcionam em geral, porque, como dissemos, elas não são mais do que açúcar sintático para promessas.
