Node.js async/await

En Node.js,async/awaites azúcar sintáctico para manejar operaciones asíncronas.

async/awaitEstá basado en Promise, pero hace que el código asíncrono parezca más código síncrono, mejorando enormemente la legibilidad y el mantenimiento del código.

asyncLa palabra clave se utiliza para declarar que una función es asíncrona, yawaitla palabra clave se utiliza para esperar la resolución (resolve) o el rechazo (reject) de una Promise.

Usarasync/awaitpuede evitar el infierno de callbacks (callback hell) y hacer que el manejo de errores sea más intuitivo.

JavaScript es de un solo hilo; cuando encuentra una tarea asíncrona (como setTimeout o una solicitud de red), se la entrega a la API del navegador para que la procese, y cuando se completa, coloca el callback en la cola de mensajes.

El bucle de eventos comprueba constantemente si la pila de llamadas está vacía; si lo está, saca un callback de la cola y lo empuja a la pila de llamadas para ejecutarlo. De esta manera no se bloquea el hilo principal y se pueden procesar los resultados asíncronos en orden.


Sintaxis básica

Función async

Cualquier función puede, agregando laasyncpalabra clave, volverse una función asíncrona:

async function myFunction() {
  return "Hello World";
}

asyncLa función siempre devuelve una Promise. Si el valor de retorno no es una Promise, se envuelve automáticamente en una Promise.

Expresión await

awaitSolo se puedeasyncusar dentro de una función async; pausa la ejecución de la función, espera a que la Promise se resuelva, y luego continúa y devuelve el resultado:

async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  return data;
}

Manejo de errores

Método try/catch

Para manejarasync/awaitlos errores, el método más común es usartry/catch:

Ejemplo

async function getUser() {
  try {
    const response = await fetch('https://api.example.com/user');
    const user = await response.json();
    return user;
  } catch (error) {
    console.error('Error fetching user:', error);
    throw error; // Puedes optar por volver a lanzar el error
  }
}

Manejar Promise directamente

También puedes manejar directamente la Promise devuelta:

Ejemplo

getUser()
  .then(user => console.log(user))
  .catch(error => console.error(error));

Ejemplo de aplicación práctica

Ejecutar múltiples operaciones asíncronas en paralelo

UsandoPromise.allcombinado conasync/awaitse pueden ejecutar múltiples operaciones asíncronas en paralelo:

Ejemplo

async function fetchMultipleUrls(urls) {
  try {
    const requests = urls.map(url => fetch(url));
    const responses = await Promise.all(requests);
    const data = await Promise.all(responses.map(r => r.json()));
    return data;
  } catch (error) {
    console.error('Error fetching data:', error);
    throw error;
  }
}

Ejemplo de operación de base de datos

Ejemplo

async function getUserAndPosts(userId) {
  try {
    const user = await User.findById(userId);
    const posts = await Post.find({ userId });
    return { user, posts };
  } catch (error) {
    console.error('Database error:', error);
    throw error;
  }
}

Mejores prácticas

  1. Siempre maneja los errores: no ignoresawaitlos errores que pueda lanzar; usatry/catcho.catch()para manejarlos
  2. Evita await innecesarios: si no necesitas esperar el resultado, puedes devolver la Promise directamente
  3. Usa el paralelismo adecuadamente: múltiples operaciones asíncronas independientes deben ejecutarse en paralelo (usandoPromise.all)
  4. Mantén el código limpio: evita una anidación demasiado profundaasync/await, extrae funciones cuando sea necesario
  5. Presta atención al impacto en el rendimiento: cadaawaitpausa la ejecución de la función; en los bucles hay que tener especial cuidado

Preguntas frecuentes

Relación entre async/await y Promise

async/awaitEs azúcar sintáctico construido sobre Promise. Cualquierasyncfunción async devuelve una Promise, y cualquierawaitpuede ir seguido de una Promise.

¿Por qué mi función async devuelve undefined?

Esto puede deberse a que olvidasteawaitantes de usarreturn, o porque la función salió antes de que la Promise se resolviera.

¿Se puede usar await en el nivel superior?

En los módulos ES (archivos que terminen en.mjsopackage.jsonMedio"type": "module"), se puede usar await directamente en el nivel superiorawait. En los módulos CommonJS, debe envolverse en unaasyncfunción.

Ejemplo

// En un módulo ES
const data = await fetchData();
console.log(data);
Otras extensiones