Entendendo o JavaScript: Async e Await

Entendendo o JavaScript: Async e Await

Pode ser que já tenha se deparado com essas novas funcionalidades do JavaScript em códigos na empresa onde trabalha ou teve que utilizar em projetos pessoais. No inicio pode ser bem confuso entender o que fazem e o propósito de cada um. Recomendo que você leia meus dois artigos, o primeiro sobre código assíncrono e síncrono, o segundo sobre Promises. Um complementa o outro. Quando entender bem esses dois conceitos vai ser bem mais fácil entender Async e Await. Vamos agora entender essas duas funcionalidades.

Async

Se lembra das Promises? Elas vieram para ajudar os desenvolvedores a construírem um código assíncrono mais legível e fácil de trabalhar. Agora com async é possível retornar promises, basta adicionar antes da declaração de uma função a palavra reservada async. Quando passamos ele antes do inicio da declaração de uma função, estamos dizendo que agora essas funções são assíncronas e sempre vão retornar uma promise. Vamos para um exemplo que vai deixar bem claro isso:

const exemplo = async () => 'Bem vindo'
console.log(exemplo());

Veja que no exemplo temos uma arrow function que retorna uma mensagem. Se você executar este código verá que ele exibira dessa maneira:

image.png

O código nos retornou a mensagem, mas além disso especificou como ela foi resolvida, ela é uma promise! Se tivéssemos uma mensagem de erro a promise seria rejeitada, reject. É importante destacar que este código ficou bem mais simples do que se estivéssemos usando uma promise. Veja como ficaria sem o async :

const exemplo = () => new Promise((resolve, reject ) => resolve('Bem vindo'))

 exemplo()
     .then(resp => console.log(resp))
     .catch(err => console.log(err));

Vamos agora para mais um exemplo, vamos usar a extensão Live Server para poder analisar no browser. E neste caso verá como será tratado a requisição. Vamos para o código:

const naoIgual = async y => {
    if (y === 'Ford') {
        throw ('Nome não pode ser igual a Ford');
    }
    return y
};

Bom agora vamos causar um erro no nosso código para ver como ele será tratado:

20210105_143501.gif

Exatamente como foi apresentado, a promise retornou status rejected, o mais interessante é que não foi necessário passar os mesmo parâmetros (resolve, reject) que temos em uma função escrita manualmente com new Promise. Apenas foi necessário incluir o async. Mas também é possível realizar o tratamento de erros utilizando do try, catch se desejar.

Podemos concluir que o async tem como objetivo retornar promises e conseguimos fazer isso de uma maneira simples. Assim envolvemos uma função em uma promise sem precisar declarar elas manualmente.

Vamos agora entender como funciona a outra palavra reservada da linguagem (funcionalidade), o await, que podemos considerar que trabalha em parceria com o async.

Await

A primeira observação que devemos fazer é que só podemos utilizar o await em funções que estão recebendo o async. O await tem um propósito bem especifico. Ele pausa a execução da função e aguarda a promise, que está dentro da função, retornar uma resposta quer seja um resolve ou um rejected. Como o próprio nome sugere ele aguarda a execução e a resposta, apenas depois da resposta ele irá para a próxima função. Vamos para outro código para que você entenda melhor:

function esperarTempo(contagem = 2500) {
    return new Promise(function (resolve) {
        setTimeout(() => resolve(), contagem)
    })
}

async function Cronometro() {

    esperarTempo(2500)
    console.log(`Async sem await exemplo 1`)

    esperarTempo(2500)
    console.log(`Apenas sem await exemplo 2`)

    esperarTempo(2500)
    console.log(`Async junto com o await `)

}

Cronometro()

O que estamos fazendo é chamando a função esperarTempo(), dentro da nossa função Cronometro() que recebe um async, nisso já sabemos que ele irá retornar uma promise. Se você executar esse código vai reparar que tudo será executado de uma vez, todas as mensagens serão exibidas juntas e apenas depois ele vai finalizar a execução das promises:

20210105_191353.gif

Agora se você quiser esperar que uma determina promise seja totalmente resolvida, para então partir para outra, você deve colocar na frente dessa função o await. Repare que agora cada função vai demorar os exatos 2.5 segundos para ser executado, pois ele só irá para a próxima função quando a anterior for totalmente finalizada:

function esperarTempo(contagem = 2500) {
    return new Promise(function (resolve) {
        setTimeout(() => resolve(), contagem)
    })
}

async function Cronometro() {

    await esperarTempo(2500)
    console.log(`Async com await exemplo 1`)

    await esperarTempo(2500)
    console.log(`Async com await exemplo 2`)

    await esperarTempo(2500)
    console.log(`Async com await exemplo 3 `) 

}

Cronometro()

O resultado pode ser visto no GIF abaixo:

20210105_191654.gif

Note que ocorreu uma demora no tempo de resposta, quem causou isso foi o await. A função Cronometro(), está sendo parada até que todas as promises esperarTempo() sejam resolvidas. Isto garante que o resultado só será exibido depois que o setTimeout atingir o tempo determinado de 2.5 segundos, que é quando cada promise é finalizada. No geral a função Cronometro() leva um total de sete segundos e meio para ser finalizada.

Espero que estes exemplos tenham esclarecido as diferenças. Agora parece que temos um código síncrono dentro da nossa função, mas não é isso, tudo ainda é assíncrono e retornam promises.

Além disso não precisamos mais ficar chamando o método .then, pois o próprio await vai realizar o tratamento da reposta para nós. Assim eliminamos cascatas de .then 😃

Conclusão

Agora já é bem claro os objetivos de cada. Lembrando que são funcionalidades novas do ES2017. Isso agiliza nosso código, facilita a criação de promises, evita cascatas de .then e nos dá liberdade para decidir como tratar nossas funções dentro do nosso código.

Agradeço mais uma vez por ler até o final, caso tenha alguma dúvida ou sugestão entre em contato comigo pelo LinkedIn ou deixe um comentário. Muito obrigado e até o próximo post! 😉🚀