Programación Asíncrona

< Anterior Siguiente >

La programación asíncrona en JavaScript es un enfoque que permite que el código se ejecute sin bloquear el hilo principal. Esto es particularmente útil en entornos del lado del cliente, donde el tiempo de respuesta es crucial para la experiencia del usuario. JavaScript maneja la asíncronía de varias maneras, incluyendo el uso de callbacks, promesas, y las palabras clave async y await.

1. Callbacks

Un callback es una función que se pasa como argumento a otra función y se ejecuta después de que se completa una operación. Este patrón era la forma más común de manejar la asíncronía en JavaScript antes de la introducción de las promesas y async/await. Aunque efectivo, puede llevar a una complejidad conocida como "Callback Hell" (infierno de callbacks), donde las funciones anidadas se vuelven difíciles de leer y mantener.

// Ejemplo de Callback
console.log("Inicio");

function fetchData(callback) {
    setTimeout(() => {
        console.log("Datos obtenidos");
        callback();
    }, 2000);
}

fetchData(() => {
    console.log("Procesando datos");
});

console.log("Fin");

// Output esperado:
// Inicio
// Fin
// Datos obtenidos
// Procesando datos
        

2. Promesas

Las promesas son objetos que representan la eventual finalización (o falla) de una operación asíncrona y su valor resultante. A diferencia de los callbacks tradicionales, las promesas proporcionan un flujo de control más limpio y evitan la necesidad de múltiples niveles de anidación.

Una promesa puede estar en uno de estos tres estados:

// Ejemplo de Promesa
let promesa = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("Promesa cumplida");
    }, 3000);
});

promesa.then((mensaje) => {
    console.log(mensaje);
}).catch((error) => {
    console.log(error);
});

// Output esperado:
// Promesa cumplida (después de 3 segundos)
        

3. Encadenamiento de Promesas

El encadenamiento de promesas permite que varias operaciones asíncronas se realicen en secuencia, con cada operación comenzando cuando se cumple la promesa anterior. Esto es útil para realizar tareas que dependen de operaciones previas.

// Ejemplo de Encadenamiento de Promesas
new Promise((resolve, reject) => {
    setTimeout(() => resolve(1), 1000);
}).then((resultado) => {
    console.log(resultado); // 1
    return resultado * 2;
}).then((resultado) => {
    console.log(resultado); // 2
    return resultado * 2;
}).then((resultado) => {
    console.log(resultado); // 4
});

// Output esperado:
// 1 (después de 1 segundo)
// 2
// 4
        

4. Async/Await

Las palabras clave async y await son una mejora sobre las promesas, proporcionando una sintaxis más clara y más fácil de entender para trabajar con operaciones asíncronas. Una función declarada con async devuelve implícitamente una promesa, y el uso de await dentro de una función async permite esperar a que una promesa se resuelva antes de continuar.

// Ejemplo de Async/Await
async function obtenerDatos() {
    try {
        let respuesta = await new Promise((resolve, reject) => {
            setTimeout(() => resolve("Datos recibidos"), 2000);
        });
        console.log(respuesta);
    } catch (error) {
        console.log(error);
    }
}

obtenerDatos();

// Output esperado:
// Datos recibidos (después de 2 segundos)
        

5. Fetch API

La Fetch API proporciona una interfaz moderna y poderosa para realizar solicitudes HTTP. A diferencia de XMLHttpRequest, fetch() devuelve una promesa que resuelve el objeto Response de la solicitud.

// Ejemplo de Fetch API
fetch('https://api.example.com/data')
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.log('Error:', error));

// Output esperado:
// { ...datos de la API... } (dependerá de la respuesta de la API)
        

6. Ejemplo Completo de Async/Await con Fetch API

Combinar async/await con la Fetch API permite manejar solicitudes de red de manera limpia y concisa.

// Ejemplo completo de Async/Await con Fetch API
async function fetchData() {
    try {
        let response = await fetch('https://api.example.com/data');
        let data = await response.json();
        console.log(data);
    } catch (error) {
        console.log('Error:', error);
    }
}

fetchData();

// Output esperado:
// { ...datos de la API... } o 'Error:' en caso de fallo