Manejo de Operaciones Asíncronas con async/await en Vue y JavaScript

Introducción a async/await

En JavaScript, async/await es un mecanismo diseñado para gestionar operaciones asíncronas. Funciona como azúcar sintáctica sobre los objetos Promise, permitiendo escribir código asíncrono con una estructura que parece síncrona. Esto mejora drásticamente la legibilidad y el mantenimiento. Además, facilita el manejo de errrores mediante bloques try...catch, capturando excepciones tanto en código síncrono como en el asíncrono.

Ejemplos Prácticos en JavaScript

1. Ejecución Asíncrona Básica

A continuación, se muestra cómo envolver una promesa para ejecutarla de forma secuencial.

// Simulación de una petición a una base de datos
async function consultarUsuario(id) {
    return new Promise((resolver) => {
        setTimeout(() => {
            resolver({ id: id, nombre: "Carlos", rol: "Admin" });
        }, 800);
    });
}

async function mostrarPerfil() {
    try {
        const usuario = await consultarUsuario(101);
        console.log(`Bienvenido, ${usuario.nombre}. Tu rol es ${usuario.rol}.`);
    } catch (err) {
        console.error("No se pudo cargar el perfil:", err);
    }
}

mostrarPerfil();

En este fragmento, consultarUsuario devuelve una promesa que se resuelve tras un retardo. La función mostrarPerfil utiliza await para pausar su ejecución hasta que los datos estén disponibles, envolviendo todo en un bloque try...catch para gestionar posibles fallos.

2. Gestión de Excepciones

Cuando una promesa es rechazada, await lanzará una excepción que debe ser interceptada.

async function obtenerConfiguracionServidor() {
    return new Promise((_, rechazar) => {
        setTimeout(() => {
            rechazar(new Error("Tiempo de espera agotado (Timeout)"));
        }, 1200);
    });
}

async function iniciarServicio() {
    try {
        const config = await obtenerConfiguracionServidor();
        console.log("Configuración cargada:", config);
    } catch (fallo) {
        console.error("Fallo crítico al iniciar:", fallo.message);
    }
}

iniciarServicio();

Si la promesa interna es rechazada, el flujo salta directamente al bloque catch, evitando que el código posterior se ejecute y permitiendo registrar el error de forma controlada.

3. Iteración sobre Colecciones

Es común necesitar procesar múltiples elementos de forma asíncrona. El bucle for...of es ideal para esto, ya que respeta la espera de cada iteración.

async function analizarArchivo(ruta) {
    return new Promise((resolver) => {
        setTimeout(() => resolver(`Análisis completado para: ${ruta}`), 500);
    });
}

async function procesarLote(rutas) {
    for (const ruta of rutas) {
        try {
            const reporte = await analizarArchivo(ruta);
            console.log(reporte);
        } catch (e) {
            console.error(`Error procesando ${ruta}:`, e);
        }
    }
}

procesarLote(["/logs/app.log", "/logs/error.log", "/logs/access.log"]);

Al usar for...of con await, garantizamos que los archivos se analicen uno tras otro. Si se requiriera paralelismo, se debería usar Promise.all combinado con map.

4. Peticiones Concurrentes

Para optimizar el tiempo de respuesta cuando no hay dependencias entre las peticiones, podemos ejecutarlas en paralelo.

async function cargarMetricas() {
    return new Promise((r) => setTimeout(() => r({ cpu: "45%" }), 600));
}

async function cargarAlertas() {
    return new Promise((r) => setTimeout(() => r({ criticas: 2 }), 900));
}

async function inicializarDashboard() {
    try {
        const [metricas, alertas] = await Promise.all([
            cargarMetricas(),
            cargarAlertas()
        ]);
        console.log("Estado del sistema:", { metricas, alertas });
    } catch (error) {
        console.error("Error al consolidar el dashboard:", error);
    }
}

inicializarDashboard();

El uso de Promise.all junto con await permite esperar a que todas las promesas se resuelavn simultáneamente, reduciendo el tiempo total de espera.

Integración en el Ecosistema Vue

Uso en Vue 2 (Options API)

En Vue 2, las llamadas a APIs dentro de los métodos deben manejar los estados de carga y los errores de forma explícita.

import { fetchUserPreferences } from "@/services/api";

export default {
  data() {
    return {
      preferencias: [],
      isLoading: false,
      errorMsg: null
    };
  },
  methods: {
    async cargarPreferencias() {
      this.isLoading = true;
      this.errorMsg = null;

      try {
        const respuesta = await fetchUserPreferences();
        
        if (respuesta.status === "success") {
          this.preferencias = respuesta.payload.map(pref => ({
            id: pref.key,
            nombre: pref.label,
            activo: pref.enabled
          }));
        } else {
          throw new Error("Respuesta de servidor inválida");
        }
      } catch (err) {
        this.errorMsg = "No se pudieron cargar las preferencias.";
        console.error(err);
      } finally {
        this.isLoading = false;
      }
    }
  }
}

El bloque finally es crucial aquí para asegurar que el indicador de carga (isLoading) se restablezca independientemente de si la petición fue exitosa o falló.

Uso en Vue 3 (Composition API)

En Vue 3, utilizando <script setup>, la lógica asíncrona se integra de manera más directa con las referencias reactivas (ref).

<script setup>
import { ref, onMounted } from 'vue';
import { fetchDashboardStats } from '@/services/stats';

const estadisticas = ref(null);
const cargando = ref(true);
const error = ref(null);

const obtenerDatos = async () => {
  cargando.value = true;
  try {
    const data = await fetchDashboardStats();
    estadisticas.value = {
      ventas: data.totalSales,
      usuarios: data.activeUsers
    };
  } catch (err) {
    error.value = "Fallo al obtener estadísticas";
    console.error(err);
  } finally {
    cargando.value = false;
  }
};

onMounted(() => {
  obtenerDatos();
});
</script>

Este enfoque mantiene el componente limpio y aprovecha el ciclo de vida onMounted para disparar la petición asíncrona una vez que el componente ha sido montado en el DOM.

Etiquetas: JavaScript vuejs async-await Promises Vue2

Publicado el 7-15 01:51