Promesas

Las promesas representa un resultado eventual de una operación asincrónica, la primera manera de interactuar con un una promesa o promise es a través del método then el cual registra el callback que recivirá la respuesta o la razón por la cual la promesa no a podido ser cumplida.

Estados

Las promesas pueden estar en 3 estados pending, fulfilled y rejected

Estados de una petición

Pending

Cuando una promesa no se haya terminado aún pero aún no ha sido rechazada. (a la espera), y la respuesta podrá ser fulfilled o rejected.

Fulfilled

Cuando la respuesta ha sido devuelta y procesada correctamente, no podrá cambiar de estado y el valor no debe cambiar (debido a la promesa, por otro procesamiento sí).

Rejected

Cuando ha ocurrido un error en la promesa, el estado de la transición no debe cambiar y debe tener una razón por la cual a sucedido el error la cual no debe cambiar. para obtener los resultados rejected utilizamos la palabra reservada catch

Cuando digo que algo no debe cambiar quiero decir que deberá ser comprobado con ===.

más información sobre promesas

Ejemplos

Ejemplo de llamada a then

const promise = new Promise((resolve, reject) => {
    resolve(123);
});
promise.then((res) => {
    console.log('I get called:', res === 123); // Devuelve: true
});
promise.catch((err) => {
    // Nuca es utilizado
});

Ejemplo de llamada a catch

const promise = new Promise((resolve, reject) => {
    reject(new Error("Algo malo a pasado"));
});
promise.then((res) => {
    // This is never called
});
promise.catch((err) => {
    console.log('Tengo una llamada: ', err.message); // Tengo una llamada: 'Algo malo a pasado'
});

Cadenas de promesas o Chain-ability of Promises

Una cadena de promesas es una manera muy útil de realizar peticiones asíncronas.

Sí una promesa hace un return la cadena hace la siguiente petición al then

Promise.resolve(123)
    .then((res) => {
        console.log(res); // 123
        return 456;
    })
    .then((res) => {
        console.log(res); // 456
        return Promise.resolve(123);
    })
    .then((res) => {
        console.log(res); // 123 : Notice that this `this` is called with the resolved value
        return Promise.resolve(123);
    })

Puedes manejar los esrrores añadiendole un método catch a la cadena.

Promise.reject(new Error('something bad happened'))
    .then((res) => {
        console.log(res); // not called
        return 456;
    })
    .then((res) => {
        console.log(res); // not called
        return Promise.resolve(123);
    })
    .then((res) => {
        console.log(res); // not called
        return Promise.resolve(123);
    })
    .catch((err) => {
        console.log(err.message); // something bad happened        
    });

También se puede hacer que un método catch continue con la cadena de promesas, de la siguiente manera:

Promise.reject(new Error('something bad happened'))
    .then((res) => {
        console.log(res); // not called
        return 456;
    })
    .catch((err) => {
        console.log(err.message); // something bad happened
        return Promise.resolve(123);
    })
    .then((res) => {
        console.log(res); // 123
    })

Cualquier error ocurrido en un then llamará al método catch. Ej.:

Promise.resolve(123)
    .then((res) => {
        throw new Error('something bad happened')
        return 456;
    })
    .then((res) => {
        console.log(res); // never called
        return Promise.resolve(789);
    })
    .catch((err) => {
        console.log(err.message); // something bad happened
    })

El hecho de que el primer then al dar un error se salte el siguiente then siendo una llamada asincrónica, nos provee con un nuevo paradicma el cual nos permite capturar mejor las excepciones asíncronas.

También es posible que algunas funciones puedan devolver promesas como por ejemplo:

function iReturnPromiseAfter1Second():Promise<string> {
    return new Promise((resolve)=>{
        setTimeout(()=>resolve("Hello world!"), 1000);
    });
}

Promise.resolve(123)
    .then((res)=>{
         // res is inferred to be of type `number`
         return iReturnPromiseAfter1Second();
    })
    .then((res) => {
        // res is inferred to be of type `string`
        console.log(res); // Hello world!
    });

En el siguiente ejemplo veremos como se hace la carga de un JSON de forma asíncrona:

// good json file
loadJSONAsync('good.json')
    .then(function (val) { console.log(val); })
    .catch(function (err) {
        console.log('good.json error', err.message); // never called
    })

// non-existent json file
    .then(function () {
        return loadJSONAsync('absent.json');
    })
    .then(function (val) { console.log(val); }) // never called
    .catch(function (err) {
        console.log('absent.json error', err.message);
    })

// invalid json file
    .then(function () {
        return loadJSONAsync('bad.json');
    })
    .then(function (val) { console.log(val); }) // never called
    .catch(function (err) {
        console.log('bad.json error', err.message);
    });

Promesas en paralelo

Como habréis observado previamente, hasta ahora todos los ejemplos que hemos visto heran peticiones en serie pero que sentido tiene eso si lo que queremos es una carga asincrónica de la información, pues no mucha es por eso que ahora veremos un ejemplo de como serían las peticiones en paralelo.

TypeScript

//-------- main.ts ---------
// Una función asincróna simulando la petición desde el servidor
function loadItem(id: number): Promise<{id: number}> {
    return new Promise((resolve)=>{
        console.log('loading item', id);
        setTimeout(() => { // simulate a server delay
            resolve({ id: id });
        }, 1000);    
    });
}

// Cadena (serie)
let item1, item2;
loadItem(1)
    .then((res) => {
        item1 = res;
        return loadItem(2);
    })
    .then((res) => {
        item2 = res;
        console.log('done');
    }); // overall time will be around 2s

// Paralelo
Promise.all([loadItem(1),loadItem(2)])
    .then((res) => {
        [item1,item2] = res;
        console.log('done')    
    }); // overall time will be around 1s

Javascript

//-------- main.js ---------
// Una función asincróna simulando la petición desde el servidor
function loadItem(id) {
    return new Promise((resolve) => {
        console.log('loading item', id);
        setTimeout(() => {
            resolve({ id: id });
        }, 1000);
    });
}
// Cadena (serie)
let item1, item2;
loadItem(1)
    .then((res) => {
    item1 = res;
    return loadItem(2);
})
    .then((res) => {
    item2 = res;
    console.log('done');
}); // overall time will be around 2s
// Paralelo
Promise.all([loadItem(1), loadItem(2)])
    .then((res) => {
    [item1, item2] = res;
    console.log('done');
}); // overall time will be around 1s

Para poder testear esto ejecutaremos el javascript en nuestro serviudor node

node main.js

Ejemplo en el playground

results matching ""

    No results matching ""