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 thens, 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ção
  • await é usado durante o tratamento da promessa
  • await deve ser usado dentro de um async embora o Chrome agora suporte “nível superior” await
  • async retornam uma promessa, independentemente do que o return seja o valor dentro da função
  • async/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 thens 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 awaits. 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.allque 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!