Promesas

32
Promesas Manejando tareas asíncronas fácilmente OpenWebinars Curso de front-end (2014) Sergio Rus @sergiorus

Transcript of Promesas

Page 2: Promesas

Una promesa es un objeto que representa un posible valor en el futuro. Se utiliza cuando se necesita operar con un resultado del que aún no se conoce su valor, algo muy típico en programación asíncrona.

¿Qué es una Promesa?

Page 3: Promesas

Una promesa puede tener 3 estados posibles:

● pendiente: el resultado aún no se conoce.● satisfecho: cuando el resultado es correcto.● rechazado: cuando el resultado es incorrecto.

¿Qué es una Promesa?

Page 4: Promesas

El estado inicial de una promesa es pendiente. Una vez que el resultado es conocido, en función de este resultado, el estado de la promesa pasa a ser satisfecho o rechazado, y este estado ya no puede volver a cambiar.

¿Qué es una Promesa?

Page 5: Promesas

¿Qué es una Promesa?

pendiente

satisfecho

rechazado

resultado conocido

Page 6: Promesas

Las promesas (también llamadas “futuros”) se usan para trabajar con código asíncrono, algo muy típico en JavaScript. De hecho se pueden encontrar en varios lenguajes de programación: JavaScript, Python, Java, Ruby, …

¿Cuándo se deben usar?

Page 7: Promesas

Gracias a las promesas, en JavaScript podemos pasar de un código profundamente anidado y difícil de entender como este...

asyncFunction1(function(error, result) { asyncFunction2(function(error, result) { asyncFunction3(function(error, result) { asyncFunction4(function(error, result) { // ... }); }); });});

¿Cuándo se deben usar?

Page 8: Promesas

… a un código mucho más legible y simple como este:

¿Cuándo se deben usar?

asyncFunction1() .then(asyncFunction2) .then(asyncFunction3) .then(asyncFunction4) .catch(handleError);

Page 9: Promesas

En JavaScript las promesas se crean con el constructor Promise. Este constructor recibe como único argumento una función, que a su vez contiene dos parámetros: resolve y reject.

¿Cómo se usan?

var promise = new Promise(function(resolve, reject) { // … });

Page 10: Promesas

Los parámetros resolve y reject son funciones para cambiar el estado de la promesa, que inicialmente es pendiente (pending). Con resolve el estado de la promesa pasa a ser satisfecho (fulfilled). Y con reject el estado cambia a rechazado (rejected).

¿Cómo se usan?

pendiente

satisfecho

rechazado

resultado conocido

resolve(value)

reject(reason)

Page 11: Promesas

¿Cómo se usan?

var promise = new Promise(function(resolve, reject) { // … if (condition) { resolve(value); } else { reject(reason); }});

La función resolve() recibe como argumento el resultado de la operación cuando ésta se ha realizado correctamente. Por contra, para indicar que hubo algún problema se usa la función reject(), pasándole como argumento un mensaje (string) o una instancia de Error.

Page 12: Promesas

La ventaja principal de las promesas es que se pueden encadenar mediante el método then(), ya que este método devuelve a su vez otra promesa. De esta manera, un código asíncrono implementado con promesas tendría un aspecto similar a este:

¿Cómo se usan?

asyncFunction1() .then(asyncFunction2) .then(asyncFunction3) .then(asyncFunction4);

Page 13: Promesas

El método then() contiene dos parámetros opcionales: onFulfilled y onRejected. Ambos son funciones.

El método then()

Page 14: Promesas

El primer parámetro, onFulfilled, recibe automáticamente el resultado devuelto por la promesa anterior cuando el estado de ésta cambia de pendiente (pending) a satisfecho (fulfilled).

El método then()

promise.then(function(value) { // … });

Page 15: Promesas

El segundo parámetro, onRejected, recibe automáticamente la razón (mensaje o instancia de Error) devuelta por la promesa anterior cuando el estado de ésta cambia de pendiente (pending) a rechazado (rejected).

El método then()

promise.then(..., function(reason) { // … });

Page 16: Promesas

Para pasar en then() únicamente la función onRejected es necesario pasar undefined como primer parámetro. Y esto es precisamente lo que hace internamente el método catch(). Este método equivale a un then() que sólo sirve para capturar errores.

El método catch()

promise.catch(function(reason) { // … });

Page 17: Promesas

Tanto then() como catch() devuelven una nueva promesa. El estado y valor de ésta depende del resultado devuelto por onFulfilled y onRejected.

then/catch

var promise2 = promise1.then(function(value1) { // … });

Page 18: Promesas

Las funciones onFulfilled y onRejected pueden devolver:

● Una promesa● Un valor● Una excepción

then/catch

Page 19: Promesas

Si onFulfilled o onRejected devuelve una promesa, entonces la promesa devuelta por then() adquiere el mismo estado y valor de dicha promesa.

onFulfilled/onRejected

var promise2 = promise1.then(function(value1) { // … return new Promise(function(resolve, reject) { // … }); });

Page 20: Promesas

Si onFulfilled o onRejected devuelve un valor x, entonces la promesa devuelta por then() pasa al estado satisfecho (fulfilled) tomando como valor el valor x.

onFulfilled/onRejected

var promise2 = promise1.then(function(value1) { // … return valor2;});

Page 21: Promesas

Si en onFulfilled o en onRejected se produce una excepción ex, entonces la promesa devuelta por then() pasa al estado rechazado (rejected) tomando como razón el objeto ex.

onFulfilled/onRejected

var promise2 = promise1.then(function(value1) { // … throw new Error(“¡error!”);});

Page 22: Promesas

A pesar de que las promesas se han incluido recientemente en la última versión de JavaScript (ES6), a día de hoy ya está soportado por la mayoría de navegadores modernos, excepto Internet Explorer.

Soporte

Page 23: Promesas

De todas formas existen multitud de bibliotecas JavaScript compatibles con la especificación de las promesas implementada en ES6, por lo que en principio se podrían usar en cualquier navegador. Por ejemplo, con este polyfill.

Soporte

Page 24: Promesas

jQuery es la excepción, ya que la implementación de las promesas incluida en jQuery no cumple la especificación de las promesas, y difiere en gran medida de la versión estándar que hemos visto hasta ahora.

jQuery

Page 25: Promesas

El problema de no implementar la versión estándar es que pueden surgir problemas al conectar (mediante el método then()) las “promesas” de jQuery con promesas estándar.

jQuery

Page 26: Promesas

jQuery implementa su propia versión de las promesas mediante el objeto constructor Deferred. Este objeto proporciona una larga de lista de métodos útiles para realizar tareas asíncronas. Entre ellos su propia versión de then() (con tres parámetros y un comportamiento diferente que el estándar).

jQuery

Page 27: Promesas

Una de las mayores diferencias entre las “promesas” de jQuery y las promesas estándar es el tratamiento de las excepciones dentro del método then().

jQuery then()

Page 28: Promesas

En las promesas estándar las excepciones se capturan sólo dentro del método then()/catch(), concretamente con la función onRejected(), pasada como 2º parámetro a then(). Es decir, las excepciones son silenciosas y no cortan el flujo de ejecución de las promesas.

jQuery then()

Page 29: Promesas

Promesas estándar

var promise2 = promise1.then(function(value1) { // … throw new Error(“¡error!”); // excepción silenciosa});

// El código sigue ejecutándose

promise2.catch(function(err) { console.log(err); // => ¡error! });

Page 30: Promesas

En las “promesas” de jQuery las excepciones no son silenciosas y tienen el comportamiento habitual: interrumpir la ejecución.

jQuery then()

Page 31: Promesas

jQuery then()

var $promise2 = $promise1.then(function(value1) { // … throw new Error(“¡error!”); // interrupción});

// A partir de aquí el código no se ejecutará

$promise2.fail(function(err) { console.log(err); });

Page 32: Promesas

La única manera segura de conectar las “promesas” de jQuery con las promesas estándar es creando una promesa estándar a partir de una “promesa” de jQuery usando el método Promise.resolve():

jQuery

var $promise = $.get(‘https://api.github.com’);var promise = Promise.resolve($promise);