Promessas em JavaScript foram uma revelação no JavaScript, oferecendo uma alternativa ao inferno de callbacks do JavaScript em que nos encontramos rapidamente. As promessas também nos permitiram introduzir e lidar melhor com tarefas assíncronas. Embora as promessas tenham sido uma melhoria em relação ao inferno do callback, elas ainda exigem muito then
s, o que pode se tornar uma bagunça. Eu realmente gostei da função async
e await
para simplificar o tratamento de promessas. Vamos dar uma olhada no async
e await
!
Noções básicas rápidas
async
é uma palavra-chave para a declaração da funçãoawait
é usado durante o tratamento da promessaawait
deve ser usado dentro de umasync
embora o Chrome agora suporte “nível superior”await
async
retornam uma promessa, independentemente do que oreturn
seja o valor dentro da funçãoasync
/await
e as promessas são essencialmente as mesmas sob o capô- Disponível agora na maioria dos navegadores, bem como no Node.js
Benefícios do async
e await
- Seu código é mais simplista, preciso
- A depuração é mais fácil graças a menos retornos de chamada
- Conversão de promessa
then
/catch
o código é fácil - Seu código pode ser mais “top down”, com menos aninhamento
Básico async
e await
Ilustração
É sempre mais fácil aprender com um exemplo, portanto, vamos dar uma olhada em um exemplo muito simples async
/ await
utilização:
// Function declared as async so await can be used async function fetchContent() { // Instead of using fetch().then, use await let content = await fetch('/'); let text = await content.text(); // Inside the async function text is the request body console.log(text); // Resolve this async function with the text return text; } // Use the async function var promise = fetchContent().then(...);
Comece declarando a função como async
; essa declaração permite que o await
seja usado por dentro. O await
é seguida por uma ação de promessa, que, obviamente, o fetch
API é. A rotina assíncrona (fetch
neste caso) é executada e a execução de outros códigos é interrompida (embora sem bloqueio) até que a ação assíncrona seja concluída. Em seguida, a função é resolvida com o return
e uma promessa é retornada.
Essencialmente, o senhor consegue manter seu código “em linha” sem a necessidade de retornos de chamada. É o async simplificado!
Conversão do Promise Handling em await
É bem provável que o senhor queira atualizar seu código de promessa quando o tempo estiver disponível. Vamos examinar a atualização da promessa para await
:
// Before: callback city! fetch('/users.json') .then(response => response.json()) .then(json => { console.log(json); }) .catch(e => { console.log('error!'); }) // After: no more callbacks! async function getJson() { try { let response = await fetch('/users.json'); let json = await response.json(); console.log(json); } catch(e) { console.log('Error!', e); } }
A conversão de cargas de then
s para await
é simples de executar e, com sorte, seu código parece um pouco sustentável!
async
/ await
Padrões
Há várias maneiras de o senhor declarar async
funções.
Função assíncrona anônima
let main = (async function() { let value = await fetch('/'); })();
Declaração de função assíncrona
async function main() { let value = await fetch('/'); };
Atribuição de função assíncrona
let main = async function() { let value = await fetch('/'); }; // Arrow functions too! let main = async () => { let value = await fetch('/'); };
Função assíncrona como argumento
document.body.addEventListener('click', async function() { let value = await fetch('/'); });
Objeto & Métodos de classe
// Object property let obj = { async method() { let value = await fetch('/'); } }; // Class methods class MyClass { async myMethod() { let value = await fetch('/'); } }
Como o senhor pode ver, adicionar async
é muito fácil e se adapta a todos os fluxos de trabalho de criação de funções!
Tratamento de erros
O uso tradicional de promessas permite que o senhor use um catch
para tratar a rejeição. Quando o usuário usa await
, sua melhor opção é usar try
/catch
:
try { let x = await myAsyncFunction(); } catch(e) { // Error! }
O antigo try
/catch
não é tão glamouroso quanto o de uma promessa catch
de uma promessa, mas é igualmente eficaz.
Paralelismo
Jake Archibald, do Google, fez excelentes observações no Documento sobre funções assíncronas sobre não ficar muito sequencial com suas await
s. A ideia é evitar o empilhamento de espera, quando possível, e, em vez disso, acionar as tarefas imediatamente e usar await
após essas tarefas forem acionadas:
// Will take 1000ms total! async function series() { await wait(500); await wait(500); return "done!"; } // Would take only 500ms total! async function parallel() { const wait1 = wait(500); const wait2 = wait(500); await wait1; await wait2; return "done!"; }
O primeiro bloco é ruim porque o segundo wait
acontece depois do primeiro wait
for concluído. O segundo bloco é um método melhor: acionar os dois wait
e o então usar await
; fazer isso permite que as funções assíncronas ocorram simultaneamente!
Promise.all
Equivalentes
Uma das minhas funções favoritas da API Promise é Promise.all
que dispara um retorno de chamada quando todas as buscas são concluídas. Não há nenhum async
/ await
equivalente, mas este post fornece um bom equivalente:
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
Lembre-se de que async
/ await
são essencialmente iguais às promessas, portanto, estamos simplesmente aguardando que a promessa agregada seja resolvida!
Agora o senhor pode usar o async
e await
em todos os principais navegadores. Essas novas palavras-chave também estão disponíveis no Node.js; versões mais antigas do Node.js podem usar a palavra-chave transform-async-to-generator
para usar o plug-in babel async
e await
hoje. As promessas ainda são excelentes, mas são mais fáceis de manter com o async
e await
!