> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/dariomaranes/intro-web-2025/llms.txt
> Use this file to discover all available pages before exploring further.

# Async/Await

> La sintaxis más moderna y legible para manejar operaciones asíncronas

# Async/Await

**Async/Await** es azúcar sintáctica sobre Promises que hace que el código asíncrono se vea y se comporte más como código síncrono. Es la forma más moderna y legible de manejar asincronismo en JavaScript.

## ¿Qué es Async/Await?

Async/await son dos palabras clave que trabajan juntas:

* **`async`**: Declara que una función es asíncrona (retorna una Promise)
* **`await`**: Pausa la ejecución hasta que una Promise se resuelva

```javascript theme={null}
async function obtenerDatos() {
  const respuesta = await fetch('/api/data');
  const datos = await respuesta.json();
  return datos;
}
```

<Note>
  `await` solo puede usarse dentro de funciones `async`. Intentar usarlo fuera generará un error de sintaxis.
</Note>

## Funciones Async

Una función `async` siempre retorna una Promise:

```javascript theme={null}
async function saludar() {
  return "Hola";
}

// Es equivalente a:
function saludar() {
  return Promise.resolve("Hola");
}

// Uso:
saludar().then(mensaje => console.log(mensaje)); // "Hola"
```

### Declaraciones de Funciones Async

<Tabs>
  <Tab title="Función Regular">
    ```javascript theme={null}
    async function miFuncion() {
      return "Hola";
    }
    ```
  </Tab>

  <Tab title="Arrow Function">
    ```javascript theme={null}
    const miFuncion = async () => {
      return "Hola";
    };
    ```
  </Tab>

  <Tab title="Método de Objeto">
    ```javascript theme={null}
    const obj = {
      async metodo() {
        return "Hola";
      }
    };
    ```
  </Tab>

  <Tab title="Event Listener">
    ```javascript theme={null}
    button.addEventListener('click', async function() {
      const datos = await obtenerDatos();
      console.log(datos);
    });
    ```
  </Tab>
</Tabs>

## Usando Await

`await` pausa la ejecución de la función async hasta que la Promise se resuelva:

```javascript theme={null}
const asyncAwaitBtn = document.getElementById("async-await");

asyncAwaitBtn.addEventListener("click", async function() {
  try {
    console.log("⏳ Cargando...");
    const response = await fetch(
      "https://jsonplaceholder.typicode.com/todos/1"
    );
    const data = await response.json();
    console.log(data);
    console.log("✅ Listo");
  } catch (error) {
    console.log(error);
  }
});
```

**Flujo de ejecución:**

1. Se imprime "⏳ Cargando..."
2. `await fetch()` pausa hasta que la petición termine
3. `await response.json()` pausa hasta que el JSON se parsee
4. Se imprime el objeto de datos
5. Se imprime "✅ Listo"

<Tip>
  Cada `await` pausa la función, pero no bloquea el hilo principal de JavaScript. Otras operaciones pueden ejecutarse mientras esperas.
</Tip>

## Comparación: Promises vs Async/Await

### Con Promises (.then)

```javascript theme={null}
function cargarUsuariosThen() {
  usersOutput.textContent = "Cargando...";
  fetch(url)
    .then(function (response) {
      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }
      return response.json();
    })
    .then(function (data) {
      console.log("Users (.then):", data);
      printUsers(data);
    })
    .catch(function (error) {
      console.log(error);
      usersOutput.textContent = error;
    });
}
```

### Con Async/Await

```javascript theme={null}
async function cargarUsuariosAsync() {
  usersOutput.textContent = "Cargando...";
  try {
    var response = await fetch(url);
    if (!response.ok) {
      throw new Error("HTTP status " + response.status);
    }
    var data = await response.json();
    console.log("Users (async/await):", data);
    printUsers(data);
  } catch (error) {
    console.log(error);
    usersOutput.textContent = error;
  }
}
```

**Ventajas de async/await:**

* Más fácil de leer - parece código síncrono
* Menos anidación
* Manejo de errores más natural con try/catch
* Mejor para debugging (call stack más claro)

## Manejo de Errores con Try/Catch

Usa bloques `try/catch` para manejar errores en funciones async:

```javascript theme={null}
async function obtenerUsuario(id) {
  try {
    const response = await fetch(`/api/users/${id}`);
    
    if (!response.ok) {
      throw new Error(`HTTP error ${response.status}`);
    }
    
    const usuario = await response.json();
    console.log('Usuario:', usuario);
    return usuario;
    
  } catch (error) {
    console.error('Error al obtener usuario:', error);
    // Puedes relanzar el error o manejar la recuperación
    throw error;
  }
}
```

### Try/Catch vs .catch()

<Tabs>
  <Tab title="Try/Catch">
    ```javascript theme={null}
    async function ejemplo() {
      try {
        const resultado = await operacionAsincrona();
        return resultado;
      } catch (error) {
        console.error(error);
      }
    }
    ```

    **Ventajas:**

    * Sintaxis familiar
    * Maneja errores síncronos y asíncronos
    * Mejor para múltiples operaciones await
  </Tab>

  <Tab title=".catch()">
    ```javascript theme={null}
    async function ejemplo() {
      const resultado = await operacionAsincrona()
        .catch(error => {
          console.error(error);
        });
      return resultado;
    }
    ```

    **Ventajas:**

    * Más conciso para un solo await
    * Permite continuar después de un error
  </Tab>
</Tabs>

## Ejecutar Promises en Paralelo

### ❌ Incorrecto: Secuencial (Lento)

```javascript theme={null}
async function obtenerTodo() {
  const usuarios = await fetch('/api/users');     // Espera 1 segundo
  const productos = await fetch('/api/products'); // Espera otro segundo
  const ordenes = await fetch('/api/orders');     // Espera otro segundo
  
  // Total: 3 segundos
}
```

### ✅ Correcto: Paralelo (Rápido)

```javascript theme={null}
async function obtenerTodo() {
  // Iniciar todas las peticiones al mismo tiempo
  const promesaUsuarios = fetch('/api/users');
  const promesaProductos = fetch('/api/products');
  const promesaOrdenes = fetch('/api/orders');
  
  // Esperar a que todas terminen
  const usuarios = await promesaUsuarios;
  const productos = await promesaProductos;
  const ordenes = await promesaOrdenes;
  
  // Total: ~1 segundo (la más lenta)
}
```

### Usando Promise.all() con Async/Await

```javascript theme={null}
async function obtenerTodo() {
  try {
    const [usuarios, productos, ordenes] = await Promise.all([
      fetch('/api/users'),
      fetch('/api/products'),
      fetch('/api/orders')
    ]);
    
    console.log('Todo cargado en paralelo');
    return { usuarios, productos, ordenes };
    
  } catch (error) {
    console.error('Al menos una petición falló:', error);
  }
}
```

<Warning>
  Si las operaciones no dependen entre sí, ejecútalas en paralelo. De lo contrario, estarás esperando innecesariamente.
</Warning>

## Await en Ciclos

### For Loop

```javascript theme={null}
async function procesarUsuarios(ids) {
  for (const id of ids) {
    const usuario = await fetch(`/api/users/${id}`);
    console.log('Usuario cargado:', usuario);
  }
  // Los usuarios se procesan uno por uno (secuencial)
}
```

### Paralelo con map()

```javascript theme={null}
async function procesarUsuarios(ids) {
  const promesas = ids.map(id => fetch(`/api/users/${id}`));
  const usuarios = await Promise.all(promesas);
  console.log('Todos los usuarios cargados:', usuarios);
  // Los usuarios se cargan todos al mismo tiempo (paralelo)
}
```

## Ejemplo Completo: Carga de Datos de Usuario

```javascript theme={null}
const btnUsersThen = document.getElementById("users-then");
const btnUsersAsync = document.getElementById("users-async");
const usersOutput = document.getElementById("users-output");
const url = "https://jsonplaceholder.typicode.com/users";

function printUsers(usersList) {
  var users = [];
  for (var i = 0; i < usersList.length; i++) {
    var user = usersList[i];
    var userDataFormatted = user.id + " - " + user.name + " (" + user.email + ")";
    users.push(userDataFormatted);
  }
  usersOutput.textContent = users.join("\n");
}

async function cargarUsuariosAsync() {
  usersOutput.textContent = "Cargando...";
  try {
    var response = await fetch(url);
    if (!response.ok) {
      throw new Error("HTTP status " + response.status);
    }
    var data = await response.json();
    console.log("Users (async/await):", data);
    printUsers(data);
  } catch (error) {
    console.log(error);
    usersOutput.textContent = error;
  }
}

btnUsersAsync.addEventListener("click", cargarUsuariosAsync);
```

## Async/Await con .finally

Puedes usar `.finally()` con async/await:

```javascript theme={null}
async function cargarDatos() {
  try {
    mostrarSpinner();
    const datos = await fetch('/api/data');
    procesarDatos(datos);
  } catch (error) {
    mostrarError(error);
  } finally {
    ocultarSpinner(); // Se ejecuta siempre
  }
}
```

O mezclarlo con Promises:

```javascript theme={null}
async function cargarDatos() {
  mostrarSpinner();
  
  const datos = await fetch('/api/data')
    .catch(error => {
      mostrarError(error);
      return null;
    })
    .finally(() => {
      ocultarSpinner();
    });
  
  if (datos) {
    procesarDatos(datos);
  }
}
```

## Top-Level Await

En módulos ES6 modernos, puedes usar `await` en el nivel superior (fuera de funciones async):

```javascript theme={null}
// En un módulo ES6
const datos = await fetch('/api/data');
console.log(datos);
```

<Note>
  Top-level await solo funciona en módulos ES6 (`<script type="module">` o archivos .mjs en Node.js).
</Note>

## Buenas Prácticas

<Steps>
  <Step title="Siempre usa try/catch">
    ```javascript theme={null}
    // ❌ Mal: Sin manejo de errores
    async function obtenerDatos() {
      const data = await fetch('/api/data');
      return data;
    }

    // ✅ Bien: Con try/catch
    async function obtenerDatos() {
      try {
        const data = await fetch('/api/data');
        return data;
      } catch (error) {
        console.error('Error:', error);
        throw error;
      }
    }
    ```
  </Step>

  <Step title="Ejecuta en paralelo cuando sea posible">
    ```javascript theme={null}
    // ❌ Lento: Secuencial
    const user = await getUser();
    const posts = await getPosts();

    // ✅ Rápido: Paralelo
    const [user, posts] = await Promise.all([
      getUser(),
      getPosts()
    ]);
    ```
  </Step>

  <Step title="No bloquees innecesariamente">
    ```javascript theme={null}
    // ❌ Mal: await innecesario
    async function sumar(a, b) {
      return await (a + b); // await es innecesario aquí
    }

    // ✅ Bien: Sin await innecesario
    async function sumar(a, b) {
      return a + b;
    }
    ```
  </Step>
</Steps>

## Cuándo Usar Async/Await

<AccordionGroup>
  <Accordion title="✅ Usa Async/Await">
    * Código nuevo que escribas
    * Múltiples operaciones asíncronas en secuencia
    * Cuando necesitas lógica compleja con await
    * Para mejor legibilidad del código
    * Cuando necesitas usar try/catch
  </Accordion>

  <Accordion title="⚠️ Considera Promises">
    * Una sola operación asíncrona simple
    * Cuando necesitas encadenar transformaciones
    * APIs que esperan Promises como retorno
    * Cuando Promise.all/race/etc. son más claros
  </Accordion>
</AccordionGroup>

## Próximos Pasos

<CardGroup cols={2}>
  <Card title="Fetch API" icon="cloud-arrow-down" href="/http/fetch-api">
    Usa async/await para hacer peticiones HTTP
  </Card>

  <Card title="Ejemplos Asíncronos" icon="code" href="/examples/async-examples">
    Ve ejemplos completos de código asíncrono
  </Card>
</CardGroup>
