Qual é a diferença entre JavaScript promises e async await?

95

Tenho usado os recursos ECMAScript 6 e ECMAScript 7 (graças ao Babel) em meus aplicativos - tanto móveis quanto web.

O primeiro passo, obviamente, foi o ECMAScript 6 níveis. Aprendi muitos padrões assíncronos, as promessas (que são realmente promissoras), geradores (não tenho certeza por que o símbolo *), etc. Destes, as promessas serviram muito bem ao meu propósito. E tenho usado bastante em meus aplicativos.

Aqui está um exemplo / pseudocódigo de como implementei uma promessa básica

var myPromise = new Promise(
    function (resolve,reject) {
      var x = MyDataStore(myObj);
      resolve(x);
    });

myPromise.then(
  function (x) {
    init(x);
});

Com o passar do tempo, descobri os recursos do ECMAScript 7, sendo um deles palavras ASYNC- AWAITchave / funções. Juntos, eles fazem grandes maravilhas. Comecei a substituir algumas das minhas promessas por async & await. Eles parecem agregar grande valor ao estilo de programação.

Novamente, aqui está um pseudocódigo de como minha função assíncrona, await se parece com-

async function myAsyncFunction (myObj) {
    var x = new MyDataStore(myObj);
    return await x.init();
}
var returnVal = await myAsyncFunction(obj);

Deixando os erros de sintaxe (se houver) de lado, ambos fazem exatamente a mesma coisa, é o que eu sinto. Quase fui capaz de substituir a maioria das minhas promessas com async, espera.

Por que é assíncrono, esperar necessário quando as promessas fazem um trabalho semelhante?

O async, espera resolve um problema maior? Ou era apenas uma solução diferente para o inferno de callback?

Como disse anteriormente, estou apto a usar promessas e assíncrono, aguardar para resolver o mesmo problema. Existe algo específico que o async espera resolvido?

Notas Adicionais:

Tenho usado o assíncrono, espera e promete em meus projetos React e módulos Node.js. O React, em especial, se antecipou e adotou muitos recursos do ECMAScript 6 e ECMAScript 7.

bozzmob
fonte
3
Seu primeiro bloco de código parece usar uma promessa para uma operação síncrona. Por que você faria isso? Síncrono é, por natureza, mais fácil de escrever código, portanto, deve haver poucos motivos para envolver uma operação síncrona em uma promessa e forçá-la a ser assíncrona.
jfriend00
@ jfriend00 Sim, você está certo. Editou o código. Obrigado.
bozzmob
2
Você ainda está tentando usar ferramentas assíncronas com funções síncronas - agora em ambos os blocos de código. Por quê?
jfriend00
@ jfriend00 Ok. Aqui eu tenho meu código gist.github.com/bozzmob/26d38b83dc37d1be37f5 . Por favor, você pode me dizer o que estou fazendo de errado?
bozzmob
10
Parece que você só precisa ler um monte para entender o que é assíncrono e esperar. Aqui estão alguns artigos: O longo caminho para Async / Await em JavaScript e Simplificando a codificação assíncrona com ES7 Async Functions e Domando a besta assíncrona com ES7 .
jfriend00

Respostas:

74

Por que é assíncrono, esperar necessário quando Promises faz um trabalho semelhante? O async, espera resolve um problema maior?

async/awaitsimplesmente oferece uma sensação síncrona para o código assíncrono. É uma forma muito elegante de açúcar sintático.

Para consultas e manipulação de dados simples, o Promises pode ser simples, mas se você se deparar com cenários onde há manipulação de dados complexos e outros itens envolvidos, é mais fácil entender o que está acontecendo se o código simplesmente olhar síncrono (para colocar de outra forma, a sintaxe em si é uma forma de "complexidade incidental" que async/awaitpode contornar).

Se você estiver interessado em saber, pode usar uma biblioteca como co(junto com geradores) para dar o mesmo tipo de sensação. Coisas como essa foram desenvolvidas para resolver o problema que, em async/awaitúltima análise, resolve (nativamente).

Josh Beam
fonte
Por favor, você pode explicar o que significa "complexidade incidental"? Além disso, quando se trata de desempenho, não há diferença entre os dois?
bozzmob
@bozzmob, shaffner.us/cs/papers/tarpit.pdf <- ele explica "complexidade incidental" ali. No que diz respeito à sua questão de desempenho, eu duvido, especialmente com o motor V8 sendo o que é. Tenho certeza de que existem alguns testes de desempenho por aí, mas não me preocuparia muito com isso. Não perca seu tempo com micro-otimização quando não for necessário.
Josh Beam
1
Muito obrigado! Esta é uma ótima informação que recebi de você. E sim, não vou olhar para micro otimizações.
bozzmob
Achei esta explicação útil nikgrozev.com/2015/07/14/…
mwojtera
33

Async / Await fornecem uma sintaxe muito mais agradável em cenários mais complexos. Em particular, qualquer coisa que lide com loops ou certas outras construções como try/catch .

Por exemplo:

while (!value) {
  const intermediate = await operation1();
  value = await operation2(intermediate);
}

Este exemplo seria consideravelmente mais complicado apenas usando Promises.

Stephen Cleary
fonte
Este é um ótimo exemplo para entender o mesmo. Então, quando se trata de desempenho, não há diferença entre os dois? E qual é a melhor para usar no código? Async Await parece melhor depois de ver o seu exemplo, pelo menos.
bozzmob
1
@bozzmob: Não há diferença no desempenho. Se você se sentir confortável em usar async / await, eu recomendo. Ainda não o uso porque não faz parte do padrão oficial.
Stephen Cleary
Sim, concordo que não faz parte do padrão, mas, no caso do ReactJS (reagir nativo especificamente), sou meio forçado a usá-lo em algumas partes do código. Portanto, metade deles são promessas e metade são aguardas assíncronas. Então, eu fiz essas perguntas a você. Obrigado pela informação necessária.
bozzmob
1
Acho que muitas pessoas ficam confusas e / ou enganadas quando ninguém usa o bloco try / catch em seus exemplos de código.
Augie Gardner
Você quer dizer assim? const getValue = value => value || operation1().then(operation2).then(getValue);
Sharcoux
13

Por que é assíncrono, esperar necessário quando Promises faz um trabalho semelhante? O async, espera resolve um problema maior? ou era apenas uma solução diferente para o inferno de callback? Como eu disse antes, posso usar Promises e Async, Await para resolver o mesmo problema. Há algo específico que Async Await resolveu?

As primeiras coisas que você precisa entender é que async/ awaitsyntax é apenas um açúcar sintático que visa aumentar as promessas. Na verdade, o valor de retorno de uma asyncfunção é uma promessa. async/ awaitsyntax nos dá a possibilidade de escrever assíncrono de maneira síncrona. Aqui está um exemplo:

Encadeamento de promessa:

function logFetch(url) {
  return fetch(url)
    .then(response => response.text())
    .then(text => {
      console.log(text);
    }).catch(err => {
      console.error('fetch failed', err);
    });
}

Async função:

async function logFetch(url) {
  try {
    const response = await fetch(url);
    console.log(await response.text());
  }
  catch (err) {
    console.log('fetch failed', err);
  }
}

No exemplo acima, o awaitaguarda até que a promessa ( fetch(url)) seja resolvida ou rejeitada. Se a promessa for resolvida, o valor é armazenado na responsevariável, e se a promessa for rejeitada, ele gerará um erro e, assim, entrará nocatch bloco.

Já podemos ver que usar async/ awaitpode ser mais legível do que encadeamento de promessa. Isso é especialmente verdadeiro quando a quantidade de promessas que usamos aumenta. O encadeamento de promessas e async/ awaitresolvem o problema do inferno de retorno de chamada e o método que você escolher é uma questão de preferência pessoal.

Willem van der Veen
fonte
7

Comparação completa com prós e contras.

JavaScript simples

  • Prós
  • Não requer nenhuma biblioteca ou tecnologia adicional
  • Oferece o melhor desempenho
  • Oferece o melhor nível de compatibilidade com bibliotecas de terceiros
  • Permite a criação de algoritmos ad hoc e mais avançados
  • Contras
  • Pode exigir código extra e algoritmos relativamente complexos

Assíncrono (biblioteca)

  • Prós
  • Simplifica os padrões de fluxo de controle mais comuns
  • Ainda é uma solução baseada em callback
  • Boa performance
  • Contras
  • Apresenta uma dependência externa
  • Pode ainda não ser suficiente para fl uxos avançados

Promessas

  • Prós
  • Simplifica muito os padrões de fluxo de controle mais comuns
  • Tratamento robusto de erros
  • Parte da especificação ES2015
  • Garante a invocação adiada de onFulfilled e onRejected
  • Contras
  • Requer APIs baseadas em retorno de chamada promisify
  • Apresenta um pequeno impacto de desempenho

Geradores

  • Prós
  • Faz com que a API sem bloqueio pareça bloqueadora
  • Simplifica o tratamento de erros
  • Parte da especificação ES2015
  • Contras
  • Requer uma biblioteca de fl uxo de controle complementar
  • Ainda requer retornos de chamada ou promessas para implementar fluxos não sequenciais
  • Requer thunkify ou promisify APIs não baseadas em gerador

Async aguardam

  • Prós
  • Faz com que a API sem bloqueio pareça um bloqueio
  • Sintaxe limpa e intuitiva
  • Contras
  • Requer Babel ou outros transpiladores e alguma configuração para ser usado hoje
Bozhinovski
fonte
De onde foi copiado? Pelo menos parte dele está na página 136-137 do livro Node.js Design Patterns (segunda edição) (ISBN-10: 1785885588)
Peter Mortensen
6

Async / await pode ajudar a tornar seu código mais limpo e mais legível nos casos em que você precisa de um fluxo de controle complicado. Ele também produz código mais amigável para depuração. E torna possível lidar com erros síncronos e assíncronos com apenastry/catch .

Recentemente escrevi este post mostrando as vantagens do assíncrono / aguardar sobre as promessas em alguns casos de uso comuns com exemplos de código: 6 razões pelas quais o JavaScript assíncrono / aguardar acaba com as promessas (tutorial)

gafi
fonte