Programación Asíncrona

async/await

async/await es la forma más moderna y elegante de trabajar con código asíncrono en JavaScript. Es azúcar sintáctico sobre las Promises que hace que el código asíncrono parezca y se escriba como código síncrono.

Si las Promises resolvieron el problema del "Callback Hell", async/await hace que trabajar con asincronía sea tan natural como escribir código normal.

¿Qué son async/await?

  • async - declara que una función es asíncrona
  • await - pausa la ejecución hasta que una Promise se resuelva

Comparación Visual

Vamos a ver un ejemplo de código con Promises y cómo se vería con async/await para que veas la diferencia:

// ❌ Con Promises (funcional pero verboso)
function obtenerDatos() {
  return fetch('/api/datos')
    .then(response => response.json())
    .then(datos => {
      console.log(datos)
      return datos
    })
    .catch(error => {
      console.log('Error:', error)
    })
}

// ✅ Con async/await (mucho más limpio)
async function obtenerDatos() {
  try {
    const response = await fetch('/api/datos')
    const datos = await response.json()
    console.log(datos)
    return datos
  } catch (error) {
    console.log('Error:', error)
  }
}

La estrategia para convertir una función con Promises a async/await es muy sencilla:

  • async declara la función como asíncrona
  • await pausa la ejecución hasta que la Promise se resuelva
  • try/catch maneja los errores

Características Importantes

  1. Una función async siempre devuelve una Promise
  2. Solo puedes usar await dentro de funciones async
  3. await pausa la ejecución hasta que la Promise se resuelva

Operaciones en Paralelo

❌ Secuencial (más lento)

async function secuencial() {
  console.time('Secuencial')
  
  const resultado1 = await esperar(1000) // Espera 1 segundo
  const resultado2 = await esperar(1000) // Espera otro segundo
  const resultado3 = await esperar(1000) // Espera otro segundo
  
  console.timeEnd('Secuencial') // ~3 segundos total
  return [resultado1, resultado2, resultado3]
}

✅ Paralelo (más rápido)

async function paralelo() {
  console.time('Paralelo')
  
  // Iniciamos todas las operaciones al mismo tiempo
  const promesa1 = esperar(1000)
  const promesa2 = esperar(1000)
  const promesa3 = esperar(1000)
  
  // Esperamos a que todas terminen
  const resultados = await Promise.all([promesa1, promesa2, promesa3])
  
  console.timeEnd('Paralelo') // ~1 segundo total
  return resultados
}

paralelo().then(resultados => console.log('Resultados paralelos:', resultados))

Promise.all con async/await

async function descargarArchivos() {
  function descargar(archivo, tiempo) {
    return new Promise(resolve => {
      setTimeout(() => {
        console.log(`📁 ${archivo} descargado`)
        resolve(`Contenido de ${archivo}`)
      }, tiempo)
    })
  }
  
  try {
    console.log('🚀 Iniciando descargas paralelas...')
    
    const archivos = await Promise.all([
      descargar('imagen1.jpg', 1000),
      descargar('imagen2.jpg', 1500),
      descargar('video.mp4', 2000)
    ])
    
    console.log('✅ Todas las descargas completadas')
    return archivos
    
  } catch (error) {
    console.log('❌ Error en alguna descarga:', error)
    throw error
  }
}

descargarArchivos()
  .then(archivos => console.log('Archivos obtenidos:', archivos.length))
  .catch(error => console.log('Error final:', error))

Errores Comunes y Cómo Evitarlos

❌ Error 1: Olvidar await

// ❌ MALO: Sin await, no espera el resultado
async function malo() {
  const resultado = esperar(1000) // Devuelve una Promise, no el valor
  console.log(resultado) // Imprime [object Promise]
  return resultado
}

// ✅ BUENO: Con await
async function bueno() {
  const resultado = await esperar(1000) // Espera y obtiene el valor
  console.log(resultado) // Imprime el valor real
  return resultado
}

❌ Error 2: No usar async en la función

// ❌ MALO: await solo funciona en funciones async
function malo() {
  const resultado = await esperar(1000) // SyntaxError!
  return resultado
}

// ✅ BUENO: Función marcada como async
async function bueno() {
  const resultado = await esperar(1000)
  return resultado
}

❌ Error 3: Hacer operaciones secuenciales innecesariamente

// ❌ MALO: Secuencial cuando podrían ser paralelas
async function malo() {
  const a = await operacion1() // Espera 1 segundo
  const b = await operacion2() // Espera otro segundo
  return [a, b] // Total: 2 segundos
}

// ✅ BUENO: En paralelo
async function bueno() {
  const [a, b] = await Promise.all([
    operacion1(), // Ambas empiezan al mismo tiempo
    operacion2()
  ])
  return [a, b] // Total: 1 segundo
}

Compatibilidad y Alternativas

Top-Level await (ES2022)

En módulos modernos, puedes usar await en el nivel superior:

// En un módulo ES6
const datos = await fetch('/api/datos')
const json = await datos.json()
console.log(json)

IIFE para navegadores antiguos

// Para usar await fuera de una función async
(async () => {
  try {
    const resultado = await miOperacionAsincrona()
    console.log(resultado)
  } catch (error) {
    console.log('Error:', error)
  }
})()

Resumen

¿Qué es async/await?

  • Sintaxis moderna para trabajar con código asíncrono
  • Azúcar sintáctico sobre las Promises
  • Hace que el código asíncrono parezca síncrono

Reglas Importantes

  • async declara una función asíncrona (siempre devuelve Promise)
  • await pausa la ejecución hasta que la Promise se resuelva
  • Solo puedes usar await dentro de funciones async

Ventajas sobre Promises

  • Código más legible y natural
  • try/catch funciona perfectamente
  • Debugging más fácil
  • Menos anidamiento

Mejores Prácticas

  • ✅ Usa Promise.all() para operaciones paralelas
  • ✅ Maneja errores con try/catch
  • ✅ Considera timeouts para operaciones críticas
  • ✅ Usa reintentos para operaciones inestables

Evolución Completa

Callbacks → Promises → async/await
   ↓           ↓          ↓
Callback    Mejor      Excelente
  Hell     legible    legibilidad

¡Con async/await has completado tu viaje por la programación asíncrona en JavaScript! Ahora tienes todas las herramientas para manejar operaciones asíncronas de manera elegante y profesional.

Examen interactivo
¿Qué es async/await?
¿Qué devuelve siempre una función async?
¿Dónde puedes usar la palabra clave await?
¿Cómo se manejan los errores en async/await?
¿Cuál es la diferencia entre estas dos funciones?
// Función A
async function funcionA() {
  const a = await operacion1()
  const b = await operacion2()
  return [a, b]
}

// Función B  
async function funcionB() {
  const [a, b] = await Promise.all([operacion1(), operacion2()])
  return [a, b]
}
¿Qué pasará con este código?
async function ejemplo() {
  console.log('1')
  await new Promise(resolve => setTimeout(resolve, 1000))
  console.log('2')
}

console.log('A')
ejemplo()
console.log('B')

🔒 Inicio sesión requerido

Para guardar tu progreso, necesitas iniciar sesión con uno de estos servicios: