Javascript, parte 14: Promesas

Un objeto Promise nos permite trabajar una tarea asincrónica que tendrá dos resultados:

  • La promesa se completa
  • La promesa falla

Método setTimeout

Este método nos da la posibilidad de ejecutar un bloque de código en un determinado momento.

Recibe dos parámetros: la función que se ejecutará y el tiempo (en milisegundos) que tardará en llamar a esa función.

Por ejemplo:

const saludar = () => {
    alert("Bienvenida/o a mi web");
};

setTimeout(saludar, 3000);

Ejemplo con parámetros:

const saludar = (nombre) => {
    alert(nombre + " bienvenida/o a mi web");
};

setTimeout(() => {
    saludar("Juanito");
}, 3000);

Como podemos ver en ambos ejemplos, el setTimeout no se ejecuta de inmediato, sino que demora una x cantidad de tiempo, la cual tenemos que indicarle en milisegundos. En el código está en 3.000 milisegundos, es decir 3 segundos.

Usando este método vamos a simular el funcionamiento de una promesa, la cual al igual que setTimeout también demorará un tiempo en darnos un resultado.

Objeto Promise

Este objeto al crearse recibe un callback que a su vez van a llamar a:

  • resolve: método que se ejecuta cuando la promesa se cumple.
  • reject: método que se ejecuta cuando la promesa falla.
const proceso = new Promise((resolve, reject) => {
    //Si SE CUMPLE llama al método resolve()
    //Si FALLA llama al método reject()
});

El método fetch() que habíamos visto la publicación pasada, aunque no lo mencioné, en realidad nos devuelve una promesa.

Por tanto los métodos then() y catch() son métodos del objeto Promise.

Método then

Vamos a crear una función que simule el resultado de una promesa:

//Función que devuelve una promesa simulada.
const simularPromesa = (nombre, milisegundos) => {
    const promesa = new Promise((resolve, reject) => {
        setTimeout(() => {
            //Una vez finalizada la promesa se ejecutará este código.
            resolve("La tarea con el nombre " + nombre + " se ha completado correctamente.");
        }, milisegundos);
    });
    return promesa;
};

Como podemos ver en el código, la pasamos a la función un nombre y el tiempo en que vamos a simular cuando finalice esa promesa.

resolve() le indicará a la promesa qué hacer cuando se complete.

También podemos pasarle información como argumento:

resolve("La tarea con el nombre: " + nombre + " se ha completado correctamente.");

Entonces teniendo en cuenta esto, podemos crear una constante y guardar el resultado de la promesa:

//Guardamos una instancia del objeto que simula la promesa.
const promesa = simularPromesa("Promesa de prueba", 5000);

Y mediante el método then() que ya vimos la publicación pasada, indicarle qué haremos una vez resuelta la promesa:

//Llamamos al método then() el cual va a dispararse una vez que la promesa se complete.
promesa.then(mensaje => {
    console.log(mensaje);
});

El código finalmente quedará:

//Función que devuelve una promesa simulada.
const simularPromesa = (nombre, milisegundos) => {
    const promesa = new Promise((resolve, reject) => {
        setTimeout(() => {
            //Una vez finalizada la promesa se ejecutará este código.
            resolve("La tarea con el nombre " + nombre + " se ha completado correctamente.");
        }, milisegundos);
    });
    return promesa;
};

//Guardamos una instancia del objeto que simula la promesa.
const promesa = simularPromesa("Promesa de prueba", 5000);

//Llamamos al método then() el cual va a dispararse una vez que la promesa se complete.
promesa.then(mensaje => {
    console.log(mensaje);
});

Método catch

Como dijimos anteriormente, las promesas no siempre pueden completarse correctamente.

En la publicación pasada habíamos visto cómo fetch() podía fallar, por ejemplo si el usuario no tenía internet, el API que se consumía no llegaba a completarse correctamente, etc.

Para eso vamos a modificar nuestra función y simular la posibilidad de que falle:

//Función que devuelve una promesa simulada.
const simularPromesa = (nombre, milisegundos, ok) => {
    const promesa = new Promise((resolve, reject) => {        
        setTimeout(() => {
            if(ok){
                //Una vez finalizada la promesa se ejecutará este código.
                resolve("La tarea con el nombre " + nombre + " se ha completado correctamente.");
            }else{
                //cuando falle la promesa se ejecutará este código.
                reject("La tarea con el nombre " + nombre + " NO se ha podido completar correctamente.");
            }
        }, milisegundos);
    });
    return promesa;
};

Y luego vamos a simular dos promesas:

//Promesa que va a simular completarse correctamente.
const promesa1 = simularPromesa("Promesa de prueba", 3000, true);
//Promesa que va a simular fallar.
const promesa2 = simularPromesa("Promesa de prueba", 5000, false);

//Promesa 1
promesa1.then(mensaje => {
    console.log(mensaje);
}).catch(error => {
    console.log(error);
});

//Promesa 2 que va a fallar.
promesa2.then(mensaje => {
    console.log(mensaje);
}).catch(error => {
    console.log(error);
});