¿Cuál es la diferencia entre las promesas de JavaScript y async await?

97

Ya he estado usando las funciones ECMAScript 6 y ECMAScript 7 (gracias a Babel) en mis aplicaciones, tanto móviles como web.

El primer paso obviamente fue a los niveles de ECMAScript 6. Aprendí muchos patrones asincrónicos, las promesas (que son realmente prometedoras), los generadores (no estoy seguro de por qué el símbolo *), etc. De estos, las promesas se adaptaron bastante bien a mi propósito. Y los he estado usando mucho en mis aplicaciones.

Aquí hay un ejemplo / pseudocódigo de cómo he implementado una promesa básica:

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

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

Con el paso del tiempo, me encontré con las características de ECMAScript 7, y una de ellas es ASYNCy AWAITpalabras clave / funciones. Estos en conjunto hacen grandes maravillas. He comenzado a reemplazar algunas de mis promesas con async & await. Parecen agregar un gran valor al estilo de programación.

Nuevamente, aquí hay un pseudocódigo de cómo se ve mi función async, await:

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

Dejando a un lado los errores de sintaxis (si los hay), ambos hacen exactamente lo mismo, es lo que siento. Casi he podido reemplazar la mayoría de mis promesas con async, awaits.

¿Por qué se necesita async, await cuando las promesas hacen un trabajo similar?

¿Async, await resuelve un problema mayor? ¿O fue solo una solución diferente para devolver la llamada al infierno?

Como dije anteriormente, puedo usar promesas y async, a la espera de resolver el mismo problema. ¿Hay algo específico que async aguarde resuelto?

Notas adicionales:

He estado usando async, awaits y promesas en mis proyectos React y módulos Node.js extensamente. React especialmente ha sido un pájaro temprano y adoptó muchas características de ECMAScript 6 y ECMAScript 7.

bozzmob
fuente
3
Su primer bloque de código parece usar una promesa para una operación sincrónica. ¿Por qué harías eso? Sincrónico es, por naturaleza, más fácil de escribir código, por lo que debería haber pocas razones para envolver una operación sincrónica en una promesa y forzarla a que ahora sea asíncrona.
jfriend00
@ jfriend00 Sí, tienes razón. Editó el código. Gracias.
bozzmob
2
Sigues intentando usar herramientas asíncronas con funciones síncronas, ahora en ambos bloques de código. ¿Por qué?
jfriend00
@ jfriend00 De acuerdo. Aquí tengo mi código gist.github.com/bozzmob/26d38b83dc37d1be37f5 . ¿Puede decirme qué estoy haciendo mal?
bozzmob
10
Parece que solo necesitas leer un montón para comprender para qué sirven async y await. Aquí están algunos artículos: El largo camino hacia asíncrono / esperan en JavaScript y Simplificación asíncrona con funciones de codificación ES7 asíncronas y doma de la bestia asíncrona con ES7 .
jfriend00

Respuestas:

75

¿Por qué se necesita async, await cuando Promises hace un trabajo similar? ¿Async, await resuelve un problema mayor?

async/awaitsimplemente le da una sensación sincrónica al código asincrónico. Es una forma muy elegante de azúcar sintáctica.

Para consultas simples y manipulación de datos, Promises puede ser simple, pero si se encuentra con escenarios donde hay manipulación de datos compleja y todo lo demás, es más fácil entender lo que está sucediendo si el código simplemente se ve como si fuera sincrónico (para decirlo de otra manera, la sintaxis en sí misma es una forma de "complejidad incidental" que async/awaitpuede eludir).

Si está interesado en saberlo, puede usar una biblioteca como co(junto con generadores) para dar el mismo tipo de sensación. Cosas como esta se han desarrollado para resolver el problema que async/awaitfinalmente se resuelve (de forma nativa).

Josh Beam
fuente
¿Puede explicarnos qué significa "complejidad incidental"? Además, cuando se trata de rendimiento, ¿no hay diferencia entre los dos?
bozzmob
@bozzmob, shaffner.us/cs/papers/tarpit.pdf <- explica la "complejidad incidental" allí. En cuanto a su pregunta de rendimiento, lo dudo, especialmente con el motor V8 siendo lo que es. Estoy seguro de que existen algunas pruebas de rendimiento, pero no me preocuparía demasiado por eso. No pierda su tiempo en microoptimización cuando no sea necesario.
Josh Beam
1
¡Muchas gracias! Esta es una gran información que obtuve de ti. Y sí, no analizará las micro optimizaciones.
bozzmob
Encontré esta explicación útil nikgrozev.com/2015/07/14/…
mwojtera
33

Async / Await proporciona una sintaxis mucho mejor en escenarios más complejos. En particular, cualquier cosa relacionada con bucles u otras construcciones como try/ catch.

Por ejemplo:

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

Este ejemplo sería considerablemente más complicado con solo usar Promesas.

Stephen Cleary
fuente
Este es un gran ejemplo para entender lo mismo. Entonces, cuando se trata de rendimiento, ¿no hay diferencia entre los dos? ¿Y cuál es mejor para usar en código? Async Await parece mejor después de ver su ejemplo al menos.
bozzmob
1
@bozzmob: No hay diferencia en el rendimiento. Si se siente cómodo usando async / await, lo recomendaría. Todavía no lo uso porque en realidad no es parte del estándar oficial.
Stephen Cleary
Sí, estoy de acuerdo en que no es parte del estándar, pero, en el caso de ReactJS (reaccionar nativo específicamente), me veo obligado a usarlo en algunas partes del código. Entonces, la mitad de ellos son promesas y la otra mitad son espera asíncrona. Entonces, les hice esas preguntas. Gracias por la información necesaria.
bozzmob
1
Creo que mucha gente se confunde y / o engaña cuando nadie usa el bloque try / catch en sus ejemplos de código.
Augie Gardner
¿Te refieres a eso? const getValue = value => value || operation1().then(operation2).then(getValue);
Sharcoux
13

¿Por qué se necesita async, await cuando Promises hace un trabajo similar? ¿Async, await resuelve un problema mayor? ¿O fue solo una solución diferente para devolver la llamada al infierno? Como dije anteriormente, puedo usar Promises y Async, Await para resolver el mismo problema. ¿Hay algo específico que haya resuelto Async Await?

Lo primero que debe comprender es que la sintaxis async/ awaites solo azúcar sintáctica que está destinada a aumentar las promesas. De hecho, el valor de retorno de una asyncfunción es una promesa.async/ awaitsyntax nos da la posibilidad de escribir de forma asincrónica y sincrónica. Aquí hay un ejemplo:

Encadenamiento de promesas:

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

Async función:

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

En el ejemplo anterior, awaitespera la promesa (fetch(url) ) se resuelva o rechace. Si la promesa se resuelve el valor se almacena en la responsevariable, y si la promesa es rechazada arrojaría un error y así entraría al catchbloque.

Ya podemos ver que usar async/ awaitpodría ser más legible que el encadenamiento de promesas. Esto es especialmente cierto cuando aumenta la cantidad de promesas que utilizamos. Tanto el encadenamiento de promesas como async/ awaitresuelven el problema del infierno de devolución de llamada y el método que elija es una cuestión de preferencia personal.

Willem van der Veen
fuente
7

Comparación completa con pros y contras.

JavaScript simple

  • Pros
  • No requiere bibliotecas ni tecnología adicionales
  • Ofrece el mejor rendimiento
  • Proporciona el mejor nivel de compatibilidad con bibliotecas de terceros.
  • Permite la creación de algoritmos ad hoc y más avanzados.
  • Contras
  • Puede requerir código adicional y algoritmos relativamente complejos

Async (biblioteca)

  • Pros
  • Simplifica los patrones de flujo de control más comunes.
  • Sigue siendo una solución basada en devolución de llamada
  • Buen rendimiento
  • Contras
  • Introduce una dependencia externa
  • Puede que aún no sea suficiente para fl ujos avanzados

Promesas

  • Pros
  • Simplifica enormemente los patrones de flujo de control más comunes.
  • Manejo robusto de errores
  • Parte de la especi fi cación ES2015
  • Garantiza la invocación diferida de onFuldered y onRejected
  • Contras
  • Requiere API promisify basadas en callback
  • Introduce un pequeño impacto de rendimiento

Generadores

  • Pros
  • Hace que la API sin bloqueo parezca una de bloqueo
  • Simplifica el manejo de errores
  • Parte de la especificación ES2015
  • Contras
  • Requiere una biblioteca de flujo de control complementaria
  • Todavía requiere devoluciones de llamada o promesas para implementar fl ujos no secuenciales.
  • Requiere thunkify o promisify API no basadas en generador

Async espera

  • Pros
  • Hace que la API sin bloqueo parezca un bloqueo
  • Sintaxis limpia e intuitiva
  • Contras
  • Requiere Babel u otros transpilers y alguna configuración para su uso actual
Johnny
fuente
¿De dónde se copió esto? Al menos una parte está en las páginas 136-137 del libro Node.js Design Patterns (segunda edición) (ISBN-10: 1785885588)
Peter Mortensen
6

Async / await puede ayudar a que su código sea más limpio y más legible en los casos en que necesite un flujo de control complicado. También produce un código más fácil de depurar. Y hace posible manejar errores síncronos y asincrónicos con solo try/catch.

Recientemente escribí esta publicación mostrando las ventajas de async / await sobre promesas en algunos casos de uso comunes con ejemplos de código: 6 razones por las que JavaScript Async / Await Blows Promises Away (Tutorial)

gafi
fuente