Contenido del curso

¿Qué se implementó en ES6?

async y await en JavaScript explicados

Resumen

Las palabras reservadas async y await llegaron con ECMAScript 8 y cambiaron la forma en que escribimos código asíncrono en JavaScript. Si vienes trabajando con promesas y quieres un control más limpio del flujo, esta sintaxis te va a facilitar la vida sin romper lo que ya conoces.

¿Qué son async y await en JavaScript?

Son palabras reservadas que se apoyan en las promesas, pero te permiten escribir código asíncrono que se lee como si fuera síncrono. La promesa sigue ahí, solo que ahora puedes pausar la ejecución de una función hasta que esa promesa se resuelva.

¿Qué hace la palabra async? Marca una función para que pueda usar await dentro y siempre devuelva una promesa, sin importar qué retornes.

¿Qué hace la palabra await? Pausa la ejecución de la función async hasta que la promesa que está esperando se resuelva o sea rechazada.

¿Cómo crear una promesa con un operador ternario?

Antes de usar async/await, necesitas una promesa que resolver. En el ejemplo de la clase se construye una función que retorna una new Promise y, en lugar de usar un if tradicional, se aprovecha el operador ternario para decidir entre resolve y reject.

js const fn = () => { return new Promise((resolve, reject) => { true ? setTimeout(() => resolve('async'), 2000) : reject(new Error('error')); }); };

Aquí pasan tres cosas interesantes:

  • El ternario reemplaza al if/else y permite un return implícito más limpio.
  • setTimeout retrasa el resolve 2 segundos, simulando una operación asíncrona.
  • El reject recibe new Error('error'), una mejor práctica que enviar un simple string porque entrega un objeto de error con stack trace.

¿Por qué usar new Error en lugar de un string?

Pasar new Error() al reject te da más información cuando algo falla: tipo de error, mensaje y rastro. Es la forma estándar de manejar fallos en promesas.

¿Cómo se usa async y await con una promesa?

Una vez que tienes la promesa, defines una función con la palabra async justo antes de los paréntesis de los argumentos. Dentro, puedes usar await para esperar el resultado de la promesa.

js const anotherFn = async () => { const something = await fn(); console.log(something); console.log('hello'); };

La clave está en que await fn() detiene la ejecución dentro de anotherFn hasta que la promesa termine. Pero, y aquí viene lo interesante, no bloquea el resto del programa por fuera de esa función.

¿En qué orden se ejecuta el código con async/await?

Para verlo en acción, se agregan dos mensajes adicionales antes y después de llamar a la función:

js console.log('before'); anotherFn(); console.log('after');

¿Cuál crees que es el orden de salida? Muchos esperarían: before, async, hello, after. Pero el resultado real es:

  1. before.
  2. after.
  3. async.
  4. hello.

¿Por qué? Porque anotherFn arranca, llega al await, y mientras la promesa espera sus 2 segundos, el hilo principal sigue corriendo y ejecuta console.log('after'). Cuando la promesa por fin se resuelve, se imprime async y luego hello.

¿await bloquea todo el programa? No. Solo pausa la función async donde está escrito. El resto del código fuera de esa función sigue ejecutándose con normalidad.

¿Qué pasa si quitas async y await?

Al quitar las palabras reservadas, la promesa queda colgando sin alguien que la espere. El orden cambia a: before, hello, after, y async aparece después por el setTimeout. Pierdes el control del flujo y la posibilidad de usar el valor que devuelve la promesa de forma ordenada.

Conceptos clave para dominar async/await

Estos son los puntos que vale la pena fijar antes de pasar a más práctica:

  • ECMAScript 8: la versión que introdujo async/await como azúcar sintáctica sobre las promesas.
  • Promesa: objeto que representa un valor que llegará hoy, mañana o nunca, con sus métodos resolve y reject.
  • Operador ternario: forma compacta de escribir un if/else que devuelve un valor, ideal con arrow functions y return implícito.
  • setTimeout: función que ejecuta un callback después de un tiempo en milisegundos, útil para simular operaciones asíncronas.
  • new Error: constructor que crea un objeto de error con mensaje y stack trace, recomendado al rechazar promesas.
  • No bloqueante: el código fuera de la función async continúa ejecutándose mientras await espera.

La mejor forma de interiorizar este flujo es abrir tu editor, copiar el ejemplo y jugar con los console.log para ver cuándo entra, cuándo espera y cuándo termina cada bloque. ¿Tú en qué orden esperabas que salieran los mensajes la primera vez?