[Win8 JavaScript] Patrón Promise

Una de las novedades que nos encontraremos a la hora de afrontar una aplicación Windows Store app , es que la mayoría de veces que interactuemos con sus APIS tendremos que hacerlo de forma asíncrona. De esta manera nuestra aplicación no afectará de forma directa al sistema y la respuesta ante el usuario será más ágil y rápida.

Un ejemplo muy gráfico sería acceder a un fichero del sistema:

[sourcecode language=»javascript»]
Windows.Storage.FileIO.readTextAsync(fichero).then(function (contenido) {
//Mostrar contenido
});
[/sourcecode]

En este ejemplo hemos utilizado la API WinRT para poder acceder al contenido de un fichero de forma asíncrona.  En cuanto se accede al contenido del fichero se lanza la función anónima que está dentro del “then”  mientras la ejecución de nuestra aplicación ha continuado. De esta manera solo mostraremos el contenido del fichero si hemos podido acceder al mismo sin bloquear la aplicación.

Por convención los nombres de las funciones asincrónicas terminan en «Async«. De esta manera puedes saber que la ejecución se producirá después que se devuelva la llamada.

Habitualmente se utilizan llamadas asíncronas para los procesos como:

  • Mostrar un cuadro de diálogo de mensaje
  • Trabajar con el sistema de archivos
  • Enviar datos a Internet y recibirlos

¿Cómo funcionan las llamadas asíncronas en las Windows Store app?

Para trabajar de forma asíncrona tanto WinRT com WinJS utilizan el patrón Promise. Este patrón se puede utilizar para gestionar las llamadas asíncronas de una manera más  fácil de seguir y encadenar.

Un objeto Promise devolverá un resultado en algún momento en el tiempo, por ejemplo la función then nos permitirá actuar cuando la promesa se cumpla y para eso disponemos de tres parámetros.

[sourcecode language=»javascript»]
promise.then( onComplete, onError, onProgress);</pre>
[/sourcecode]

  • onComplete: función que se lanza cuando se cumple la promesa.
  • onError:  función que se lanza cuando hay un error.
  • onProgress : función que se lanza cuando se notifica un cambio en el progreso de la promesa.

Siguiendo con el ejemplo anterior veremos como capturar los errores y las notificaciones de progreso.

[sourcecode language=»javascript»]
Windows.Storage.FileIO.readTextAsync(fichero).then(
function complete(res) {
document.getElementById("result").textContent = res;
},
function error(res) {
document.getElementById("error").textContent = "Error";
},
function progress(res) {
document.getElementById("progress").textContent = "Progress";
});
[/sourcecode]

Otra función que podemos utilizar es done.

[sourcecode language=»javascript»]
promise.done(onComplete, onError, onProgress);
[/sourcecode]

La diferencia es que en el caso de un error en el procesamiento, la función then devuelve un objeto promise en el estado de error pero no inicia una excepción. Mientras que el método done inicia una excepción si no se proporciona una función de error.

Además then devuelve una promesa lo que nos permite el encadenamiento de promesas, mientras que done devuelve undefined. Por eso se recomienda usarthen para una etapa intermedia de la operación (por ejemplo .then().then()) y done para la etapa final de la operación (por ejemplo, .then().then().done()).

Encadenamiento de Promise

Como then devuelve una promesa, puedes encadenar mas de una función asíncrona para su ejecución.

[sourcecode language=»javascript»]
var divResultado = document.getElementById("result");

WinJS.xhr({ url: "http://localhost:32999/api/values" })
.then(function (result) {
divResultado.innerText = result.responseText;
return result;
})
.then(function (result) {
divResultado.style.backgroundColor = "green";
},
function (error) {
divResultado.style.backgroundColor = "red";
divResultado.innerText = "Error";
});
[/sourcecode]

En este ejemplo se puede comprobar como realizar una llamada asíncrona a un servicio de datos externo, en el primer then trataremos los datos, el segundo then destacaremos en la interfaz que los datos se han cargado correctamente y luego tendremos una función  para tratar las excepciones.

Es recomendable encadenar las promesas y no anidarlas para una mejor lectura del código y un mejor seguimiento de los errores.

Si lo preferimos podemos tener una función global para el tratamiento de los errores.

[sourcecode language=»javascript»]
WinJS.xhr({ url: "http://localhost:32999/api/values" })
.done(function (result) {
divResultado.innerText = result.responseText;
});

WinJS.Promise.onerror = function errorhandler(event) {
var ex = event.detail.exception;
var promise = event.detail.promise;
};
[/sourcecode]

Pero si utilizamos el evento onerror para capturar el error en tiempo de ejecución, estaremos limitando un poco el control de los errores de las llamadas asíncronas.

Por último hay que tener en cuenta que para procesos muy largos la mejor opción es utilizar tareas en segundo plano.

Para más información visitar la página oficial de msdn donde hay gran cantidad de información y ejemplos sobre el desarrollo de aplicaciones Windows Store App

Update: 22/10/2012
Por si no queda muy claro, Promise no hace que nuestro código sea asíncrono. Promise es una implementación del Patrón Observable y nos ayuda a gestionar nuestras llamadas asíncronas de una manera más sencilla. Las funciones asíncronas son las própias de WinRT acabadas en «Async«.

2 comentarios en “[Win8 JavaScript] Patrón Promise”

  1. Muy buen articulo Marc. Para los ignorantes de javascript como yo nos va de fabula.. He trabajado con async desde la ctp de silverlight 4 y la parte cliente c# la tengo asumida pero el mundo javascript me queda lejos aun 😉 .

    1. Gracias Benjami, alfinal independientemente del lenguaje y la platafrma, las buenas practicas y el sentido comun hacen que todos vayamo en el mismo sentido 🙂

Responder a Benjami Adell Cancelar respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio