Usando async e await em JavaScript

No meu tutorial anterior, cobrimos o básico das promessas em JavaScript. Concluí o artigo dizendo que as promessas nos permitem executar nosso código de forma assíncrona.

Neste tutorial, aprenderemos sobre o async e await palavras-chave em JavaScript que nos permitem usar promessas de forma eficaz e escrever um código assíncrono mais limpo.

Definindo async Funções

Vamos começar a discussão com funções assíncronas. Considere a seguinte função de saudação:

1
function greet() {
2
  return "Hello, World!";
3
}
4

5
// Outputs: Hello, World!

6
console.log(greet());

É apenas uma função JavaScript regular que todos nós já vimos antes. Tudo o que ele faz é retornar uma string que diz “Hello, World!”. No entanto, podemos transformá-lo em uma função assíncrona simplesmente adicionando a palavra async antes dele, como mostrado abaixo:

1
async function greet() {
2
  return "Hello, World!";
3
}
4

5
// Outputs: Promise { : "fulfilled", : "Hello, World!" }

6
console.log(greet());

Desta vez, a função retorna um Promise objeto com sua propriedade de estado definida como cumprida e valor definido como Olá Mundo!. Em outras palavras, a promessa foi resolvida com sucesso.

Ainda estamos retornando a string “Hello, World!” dentro da definição da função. No entanto, o uso de async palavras-chave significa que os valores retornados serão agrupados em um Promise objeto. O valor da promessa resolvida seria o mesmo valor que retornamos do async função.

Você também pode retornar uma promessa de sua própria forma async funcionar como mostrado abaixo:

1
async function greet() {
2
  return Promise.resolve("Hello, World!");
3
}
4

5
// Outputs: Hello, World!

6
greet().then((value) => console.log(value));

Basicamente, o async A palavra-chave nos ajuda a definir funções que sempre retornarão uma promessa. Você mesmo pode retornar uma promessa explicitamente ou deixar a função agrupar qualquer valor retornado que não seja uma promessa em uma promessa.

O await Palavra-chave

Qualquer async função pode conter zero ou mais await expressões. É importante lembrar que o await a palavra-chave só é válida dentro async funções. O await palavra-chave é usada para esperar por um Promise para resolver ou rejeitar e então obter o valor cumprido.

Nós usamos o await palavra-chave com a seguinte sintaxe:

A expressão pode ser nativa Promise nesse caso, seria usado diretamente e esperado nativamente. Não haveria chamadas implícitas para then() nesse caso. A expressão pode ser um objeto entável, caso em que um novo Promise será construído chamando o then() método. A expressão também pode ser um valor não acionável. Neste caso, um já cumprido Promise serão construídos para nosso uso.

Digamos que uma promessa já foi cumprida. A execução do async função ainda será pausada até o próximo tick. Isso é importante ter em mente.

Aqui está um exemplo de uso do await palavra-chave dentro de um async função:

1
async function greet() {
2
  let greeting = await "Hello, World!";
3
  return greeting;
4
}
5

6
// Outputs: [Function: Promise]

7
console.log(greet().constructor);
8

9
// Outputs: Hello, World!

10
greet().then((msg) => console.log(msg));

Aqui está outro exemplo de uso do await palavra-chave com um async função ao usar explicitamente uma promessa:

1
async function greet() {
2
  let greeting = new Promise((resolve) => {
3
    setTimeout(() => {
4
      resolve("Hello, World!");
5
    }, 2000);
6
  });
7
  
8
  return greeting;
9
}
10

11
// Outputs: [Function: Promise]

12
console.log(greet().constructor);
13

14
// Outputs: Hello, World!

15
greet().then((msg) => console.log(msg));

Desta vez, usamos explicitamente uma promessa que resolve em 2 segundos. Portanto, a saudação “Hello, World” é impressa após dois segundos.

Compreendendo a Ordem de Execução das Declarações

Agora escreveremos duas funções de saudação diferentes e veremos a ordem em que elas exibem os resultados.

1
function n_greet(person) {
2
  return `Hello, ${person}!`;
3
}
4

5
async function a_greet(person) {
6
  let greeting = await `Hello, ${person}!`;
7
  return greeting;
8
}

Nossa primeira função n_greet() é uma função normal que retorna uma string como saída. Nossa segunda função é um async função que usa uma expressão após o await palavra-chave. O valor de retorno neste caso é uma promessa já cumprida.

Aqui está o trecho de código que chama todas essas funções e registra a saída:

1
a_greet("Andrew").then((msg) => console.log(msg));
2
console.log(n_greet("Adam"));
3

4
/* Output in order:

5
Hello, Adam!

6
Hello, Andrew! */

O n_greet() chamada de função que cumprimentou Adam estava no final. No entanto, ele é saudado primeiro na saída. Isso ocorre porque a chamada de função retorna diretamente uma string.

O a_greet() A chamada de função que cumprimentou Andrew estava no início e resultou na construção de uma promessa já cumprida. No entanto, a execução ainda foi pausada até o próximo tick. É por isso que a saudação de saída ocorre após a saudação para Adam.

Agora, vamos definir um pouco mais complicado async função com várias instruções. Uma dessas declarações terá o await palavra-chave. Você verá que o uso de await palavra-chave dentro de um async A função pausa a execução de outras instruções que vêm após a await declaração.

1
function timeout(ms) {
2
    return new Promise(resolve => setTimeout(resolve, ms))    
3
}
4

5
async function aa_greet(person) {
6
  console.log("Before Await..."); 
7
  await timeout(2000);
8
  let greeting = `Hello, ${person}!`;
9
  console.log("After Await...");
10
  
11
  return greeting;
12
}
13

Nosso async função aqui contém uma promessa explicitamente definida precedida pelo await palavra-chave. Isso significa que await A palavra-chave aguardará que a promessa seja cumprida e, em seguida, retornará o valor cumprido. A promessa levará 2 segundos para ser cumprida, então devemos ver “Depois de Aguardar…” em nosso log de console após cerca de 2 segundos.

Aqui está o trecho de código que registrará algumas declarações em torno de nosso async função:

1
console.log("Before Greeting Function...");
2
aa_greet("Monty").then((msg) => console.log(msg));
3
console.log("After Greeting Function...");
4

5
/* Output in Order

6
23:42:15.327 Before Greeting Function...

7
23:42:15.331 Before Await...

8
23:42:15.331 After Greeting Function...

9
23:42:17.333 After Await...

10
23:42:17.333 Hello, Monty! */

A string “Before Greeting Function…” é registrada primeiro porque esta é a primeira chamada que fazemos. Depois disso, chamamos nosso aa_greet() função. Isso resulta na saída da string “Before Await…”. Em seguida, o navegador encontra o await palavra-chave. Então, espera que a promessa seja resolvida. Nesse meio tempo, a execução de código fora do aa_greet() função continua. É por isso que obtemos a string “Após a função de saudação…” como saída na próxima entrada de log.

Depois que a promessa é resolvida, o navegador continua a execução e obtemos “After Await…” como saída. Finalmente, nossa saudação resolvida é retornada como uma promessa porque estamos usando um async função. Nós chamamos o then() método nesta promessa resolvida e registre “Olá, Monty!” para o console.

Usando async e await Com a API de busca

Um caso de uso comum para a palavra-chave await é buscar dados de uma API remota. Isso permite um código muito mais limpo do que callbacks aninhados ou encadeamento de promessas.

1
async function getData() {
2
    // use the fetch API to fetch data from an API endpoint

3
    const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
4
    
5
    // check if the response is okay (HTTP status code 200-299)

6
    if (!response.ok) {
7
      throw new Error(`HTTP error! Status: ${response.status}`);
8
    }
9
    
10
    // parse the response as JSON

11
    const data = await response.json();
12
    
13
    return data;
14
}

Nesta função, primeiro esperamos a resposta inicial a uma consulta de API. Se a resposta estiver correta, aguardamos os dados de resposta completos como JSON. Retornamos os dados JSON, mas lembre-se de que, como essa é uma função assíncrona, na verdade estamos retornando uma promessa que eventualmente resolve esses dados. Portanto, se você quiser acessar os dados resultantes, terá que usar algo como a palavra-chave await novamente!

1
const data = await getData();

Pensamentos finais

Depois de aprender sobre o Promise objeto no tutorial anterior, discutimos async funções e o await palavra-chave neste tutorial. Agora você deve ser capaz de escrever o seu próprio async funções que utilizam o await palavra-chave para implementar o comportamento baseado em promessa com um código mais limpo e legível.

Deixe uma resposta