Compartir en Twitter
Go to Homepage

CÓMO RESOLVER O RECHAZAR PROMISES EN JAVASCRIPT: TUTORIAL

January 1, 0001

Introducción a las Promises en JavaScript

En el desarrollo moderno con JavaScript, el manejo eficiente de operaciones asíncronas es fundamental para construir aplicaciones robustas y responsivas. Las Promises en JavaScript son una herramienta esencial que permite gestionar estas operaciones de manera clara y estructurada. Una Promise es un objeto que representa la eventual finalización o fracaso de una operación asíncrona, facilitando la escritura de código más legible y mantenible.

Una Promise puede encontrarse en uno de tres estados: pendiente, resuelta o rechazada. Inicialmente, una Promise está en estado pendiente, indicando que la operación asíncrona aún no ha finalizado. Posteriormente, puede resolverse exitosamente, pasando al estado resuelto, o puede ser rechazada si ocurre un error durante la ejecución.

Para crear una Promise, se utiliza el constructor Promise, que recibe una función con dos parámetros: resolve y reject. La función resolve se invoca cuando la operación asíncrona concluye correctamente, mientras que reject se utiliza para indicar que la operación ha fallado.

const promesa = new Promise((resolve, reject) => {
    setTimeout(() => {
        const exito = true;
        if (exito) {
            resolve("Operación completada con éxito.");
        } else {
            reject("La operación falló.");
        }
    }, 2000);
});

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

Este ejemplo simula una operación asíncrona que se completa después de 2 segundos. Si la operación es exitosa, se llama a resolve con un mensaje de éxito; en caso contrario, se invoca reject con un mensaje de error. Posteriormente, se manejan ambos casos con los métodos then y catch.

Estados y manejo de Promises

Comprender los estados de una Promise es crucial para su manejo adecuado. Una Promise comienza en estado pendiente y puede transitar a resuelta o rechazada, pero una vez que cambia de estado, este no puede modificarse. Esta característica garantiza la inmutabilidad del resultado de la operación asíncrona.

Para manejar el resultado de una Promise, se utilizan los métodos then y catch. El método then se ejecuta cuando la Promise se resuelve exitosamente, recibiendo el valor resultante. Por otro lado, catch se ejecuta si la Promise es rechazada, permitiendo capturar y manejar errores.

fetch("https://jsonplaceholder.typicode.com/posts")
    .then((response) => response.json())
    .then((data) => console.log(data))
    .catch((error) => console.error(error));

En este fragmento, se realiza una solicitud HTTP para obtener publicaciones. Si la solicitud es exitosa, los datos se procesan y muestran; si ocurre un error, se captura y muestra en consola.

Resolución y rechazo de Promises

Para resolver una Promise, se utiliza el método resolve, que acepta un valor con el cual la Promise se considera cumplida. Alternativamente, para rechazar una Promise, se emplea el método reject, que generalmente recibe un objeto Error para facilitar la identificación y manejo del problema.

const tarea = new Promise((resolve, reject) => {
    const exito = true;
    if (exito) {
        resolve("Tarea completada");
    } else {
        reject(new Error("Error en la tarea"));
    }
});

tarea
    .then((resultado) => console.log(resultado))
    .catch((error) => console.error(error));

Además, con funciones asíncronas y la palabra clave await, es posible esperar la resolución de una Promise de forma más legible:

async function ejecutarTarea() {
    const resultado = await Promise.resolve("Tarea completada");
    console.log(resultado);
}

ejecutarTarea();

Encadenamiento de Promises para operaciones secuenciales

Una de las ventajas más poderosas de las Promises es la capacidad de encadenarlas para ejecutar operaciones asíncronas de forma secuencial. Esto se logra utilizando múltiples llamadas a then, donde el resultado de una Promise se pasa a la siguiente.

const promesa1 = new Promise((resolve) => setTimeout(() => resolve(1), 1000));

const promesa2 = (valor) =>
    new Promise((resolve) => setTimeout(() => resolve(valor + 1), 1000));

promesa1.then(promesa2).then((resultado) => console.log(resultado)); // Imprime 2 después de 2 segundos

Este patrón permite construir flujos de trabajo complejos y legibles, evitando el anidamiento excesivo de callbacks.

Ejecución concurrente con Promise.all

Para ejecutar múltiples Promises en paralelo y esperar a que todas se resuelvan, se utiliza el método Promise.all. Este método recibe un array de Promises y retorna una nueva Promise que se resuelve con un array de resultados cuando todas las Promises se han cumplido.

const p1 = Promise.resolve(3);
const p2 = 42;
const p3 = new Promise((resolve) => setTimeout(resolve, 100, "foo"));

Promise.all([p1, p2, p3]).then((valores) => {
    console.log(valores); // [3, 42, "foo"]
});

Es importante destacar que si alguna Promise es rechazada, Promise.all también se rechaza inmediatamente con el motivo del primer rechazo.

Manejo adecuado de errores en Promises

El manejo correcto de errores es esencial para evitar fallos inesperados en las aplicaciones. Se recomienda utilizar catch para capturar errores y finally para ejecutar código que debe correr independientemente del resultado.

const promesa = new Promise((resolve, reject) => {
    setTimeout(() => reject("Error inesperado"), 2000);
});

promesa
    .then((resultado) => console.log("Resultado:", resultado))
    .catch((error) => console.error("Error:", error))
    .finally(() => console.log("Operación finalizada"));

Este enfoque garantiza que los errores sean manejados y que se realicen tareas de limpieza o actualización necesarias.

Conclusiones

El manejo de Promises en JavaScript es una habilidad fundamental para el desarrollo moderno. Entender sus estados, métodos de resolución y rechazo, así como técnicas para encadenar y ejecutar Promises concurrentemente, permite escribir código asíncrono más limpio y eficiente.

El uso de métodos como then, catch, finally, Promise.all y Promise.race facilita la gestión de flujos asíncronos complejos y el manejo robusto de errores. Incorporar estas prácticas en tus proyectos mejorará la calidad y mantenibilidad de tu código.

Dominar las Promises te permitirá afrontar con confianza los desafíos del asincronismo en JavaScript, optimizando el rendimiento y la experiencia del usuario en tus aplicaciones.