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
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