Añade promises a tu código Javascript de manera fácil con RSVP
En este post vamos a ver un ejemplo rápido para implementar Promises en las clases y en las funciones que programamos. Esto hará que nuestras funciones y clases sean más sencillos de usar por nosotros mismos u otros programadores. Para ello utilizaremos la librería RSVP que se parece bastante a la implementación de Promises que será la oficial nativa para las futuras versiones de Javascript. En el ejemplo veremos cómo desvincular la lógica de nuestro interfaz gráfico mediante el uso de Promises.
Implementación clásica
El escenario es el siguiente: Tenemos una página web que consulta el tiempo en Santander cuando el usuario pulsa un botón mediante una llamada asincrona a un API en Internet. Vamos a usar un interfaz de usuario muy austero: simplemente un botón y un textarea donde mostraremos lo que nos resulta de la llamada al API en Internet.
<button onclick="callApiWeather()">Check weather in Santander (Spain)</button><br>Result:<br> <textarea id="result" cols="80" rows="10"></textarea>
La función Javascript hace la llamada al servicio y muestra el resultado modificando el contenido del textarea o bien mostrando una ventana tipo Alert
//Original code: http://stackoverflow.com/questions/8567114/how-to-make-an-ajax-call-without-jquery function callApiWeather() { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function () { if (xmlhttp.readyState == XMLHttpRequest.DONE) { if (xmlhttp.status == 200) { document.getElementById("result").innerHTML = xmlhttp.responseText; } else if (xmlhttp.status == 400) { alert('There was an error 400'); } else { alert('something else other than 200 was returned'); } } }; xmlhttp.open("GET", "http://api.openweathermap.org/data/2.5/weather?q=Santander,es&appid=ed2742b439caab5778488daaf610d227", true); xmlhttp.send(); }
Es fácil ver que tenemos un problema: nuestra función es dependiente del interfaz en que lo utilizamos. En las lineas 8, 11 y 14 estamos accediendo directamente a los objetos document y window. Vamos a desvincular las dos capas, y para ello vamos a hacer que nuestra función callApiWeather devuelva una Promise.
Transformando nuestro código para usar Promises
¿Cómo utilizaríamos esa función si nos devolviera una Promise? Muy sencillo: vamos a crear una nueva función displayWeather que llamaremos desde nuestro botón, y que conociendo la estructura del interfaz de usuario, lo utilizará para mostrar los resultados de la llamada a callApiWeahter:
function displayWeather() { callApiWeather() .then(function (result) { document.getElementById("result").innerHTML = result; }, function (errorMsg) { alert(errorMsg); }); }
Y modificamos nuestro botón para que llame a la nueva función:
<button onclick="displayWeather()">Check weather in Santander (Spain)</button>
Ahora llega la hora de modificar nuestra función callApiWeather para hacerla independiente del interfaz de usuario. Lo primero que debemos hacer es incluir la librería RSVP.js
<script src="https://cdn.jsdelivr.net/rsvp/3.0.6/rsvp.min.js"></script>
A continuación vamos a envolver el código de nuestra función dentro de la definición de la Promise siguiendo esta estructura:
function ourOriginalFunction() { return new RSVP.Promise(function(fulfill, reject){ //Original code // ... // ... // If everything is ok, we call fulfill with the result as argument // If something is wrong, we call reject with the error message as argument // .. }); }
Nuestro código funcionando mediante promises quedaría como sigue:
function callApiWeather() { return new RSVP.Promise(function(fullfill, reject){ var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function () { if (xmlhttp.readyState == XMLHttpRequest.DONE) { if (xmlhttp.status == 200) { fullfill(xmlhttp.responseText); } else if (xmlhttp.status == 400) { reject('There was an error 400'); } else { reject('something else other than 200 was returned'); } } }; xmlhttp.open("GET", "http://api.openweathermap.org/data/2.5/weather?q=Santander,es&appid=ed2742b439caab5778488daaf610d227", true); xmlhttp.send(); }); }
Podeis ver aquí todo el código funcionando (con alguna pequeña adaptación para que funcione en JSFiddle. Hay otras maneras de implementarlo, pero esta es la más sencilla, y te permite adaptar código que ya tienes funcionando a los nuevos tiempos mediante el uso de promises para comunicar sus resultados. Además es muy útil cuando tenemos que separar responsabilidades entre distintas clases.
No comments yet.