Funciones asíncronas con ES7 async/await

Escribir código asíncrono en JavaScript es tedioso, o al menos lo era ya que hasta la versión 6 de ECMAScript dependíamos en gran parte del uso de funciones de devolución de llamada, más conocidas como callbacks. Con ES6 se introdujeron las promesas y los generadores, los cuales ayudan a que nuestro código sea más fácil de entender y más simple de escribir.

En este breve post vamos a repasar la propuesta de ECMAScript 2016 (ES7 para los colegas) para mejorar nuestra experiencia en programación asíncrona con async/await.

 

es2016-es7-async-await

 

Funciones asíncronas

El funcionamiento de este tipo de funciones es bastante simple, al igual que sucede con las promesas, las funciones asíncronas pueden bloquear la ejecución del código hasta disponer del valor devuelto por la función, de hecho, una función asíncrona siempre devolverá siempre una Promise.

NOTA: Si aún no sabes de que van las promesas te aconsejo que antes de seguir leyendo le des un repaso al tema. Puedes empezar a documentarte un poco sobre las promesas de ES6 en este artículo.

 

Async/await

Disponemos de dós métodos para trabajar con este tipo de funciones, async y await. Su uso es bastante sencillo, utilizaremos async para declarar las funciones asíncronas, y dentro de estas funciones utilizaremos await para suspender la ejecución hasta que la expresión que le sigue devuelva un valor. Veamos un ejemplo sencillo.

async function asyncFunction () {
  const foo = await asyncOperation()
  return foo
}

Al ejecutar el código anterior, la función asyncFunction() bloqueará la ejecución del resto de código del programa hasta disponer del valor devuelto por su función interna asyncOperation(). Sencillo, cierto?

Al igual que sucede con las promesas, también tenemos la posibilidad de concatenar multiples operaciones y esperar sus valores de forma secuencial.

async function asyncFetchData (url) {
  const req = await fetch(url)
  const data = await req.map(getJSON)
  return JSON.parse(data)
}

En este ejemplo, la ejecución se detendrá hasta que req obtenga una respuesta. Una vez tengamos la respuesta, se ejecutará la siguiente linea volviendo a bloquear la ejecución hasta disponer de los datos del ‘mapeo’.

Este tipo de funciones se vuelven realmente interesantes cuando tratamos con iteraciones o bucles ya que podremos ejecutar diversos métodos de manera secuencial, es decir, uno tras otro, esperando a que cada uno devuelva un resultado antes de ejecutar el siguiente.

async function asyncFetchData (url) {
  const req = await fetch(url)
  req.forEach(async (doc, index) => {
    await asyncOperation(doc)
  })
}

 

Manejo de errores

El manejo de errores en este tipo de funciones es realmente sencillo y el código resultante es súper legible y elegante. La solución es incluir en nuestro código en un simple try/catch al igual que en el ejemplo que sigue.

async function asyncFetchData (url) {
  try {
    const req = await fetch(url)
    const data = await req.map(getJSON)
    return JSON.parse(data)
  } catch(error) {
    console.error(error)
  }
}

 

Conclusión

El pasado eran callbacks, el presente son promesas y el futuro son funciones asíncronas. Sin duda estas funciones hacen que nuestro código sea mucho más elegante y comprensible y con una sintaxis más similar a con la que escribimos código asíncrono.

Aunque actualmente no son un estándar, afortunadamente no tenemos que esperar al 2020 para poder utilizarlas, gracias transpilers como Babel podemos utilizarlas a día de hoy sin problemas.

Hasta la próxima!

  • santiago martini

    Excelente tu explicación, muchas gracias!!