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 {
|
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.