El patrón Promise

Actualización 19/3/2014: Finalmente los promises se han confirmado para el estándar ECMAScript 6, dentro de poco serán nativos en Javascript 😀

Actualización 7/10/2016: Los promises ya son estándar y están implementados en los navegadores!!!

PROBLEMA

Recientemente he tenido que implementar un sistema MVC en Javascript para simplificar el desarrollo sobre una plataforma y me he encontrado con el problema de que las llamadas asíncronas a servidor rompían la simpleza del código, tras un análisis identifiqué cuatro problemas:

1 – Ensuciar la API

Todas las llamadas reciben un último argumento que es el callback:

var dir = new Directory('file:///home/user/Desktop');
dir.browse(function(dir, items) {
  // ...
});

Con ésto la API resulta confusa desde el punto de vista de la simpleza y de la semántica. Semánticamente una función recibe la información mínima indispensable para devolver un dato relacionado a lo que se le ha solicitado, como vemos no es el caso en métodos asíncronos:

void Directory.browse(Function callback);
void File.getContent(String encoding, Function callback);
void File.getPermission(Function callback);

2 – Llamadas anidadas

En muchas ocaciones deberemos ejecutar una llamada al acabar otra, ésto nos obliga a anidar callbacks:

var file = new File();
file.isReadable(function(permission) {
  if (permission) {
    file.getContent(function(content) {
      // do something with the content
    });
  }
});

A medida que vamos añadiendo niveles de profundidad ésto se vuelve muy confuso.

3 – Llamadas concurrentes

También necesitaremos realizar llamadas asíncronas paralelas y ejecutar una acción al acabar todas:

var isFile1Done = false;
var isFile2Done = false;

function testIsOver() {
  if (isFile1Done && isFile2Done) {
    // Both files loaded.
  }
}

File.get('http://www.somedomain.com/file1', function() {
  isFile1Done = true;
  testIsOVer();
});
File.get('http://www.somedomain.com/file2', function() {
  isFile2Done = true;
  testIsOVer();
});

Como podemos ver algo tan sencillo como dos peticiones paralelas necesitan mucho código para manejarlas.

4 – Gestión de errores

Es traumática la forma de gestionar errores mediante callbacks, el método más extendido que he visto ha sido el de nodejs, el primer argumento de cada callback es el objeto Error si es que hubo alguna excepción, lo que me parece horrible ya que cada función debe confirmar que su primer argumento es undefined para asegurar que no han habido errores:

File.get('http://www.somedomain.com/file2', function(error, file) {
  if (error) {
    // Show blue screen of death
  }
  // do something with file.
});

SOLUCION

Queda claro que las peticiones asíncronas son necesarias en cliente y servidor ya que permiten al programa continuar trabajando mientras espera la respuesta a la petición, pero éstos problemas podrían dificultar la manutención del código. Y aquí es donde viene a ayudarnos el Patrón Promise. El patrón Promise asiste a una función que no puede devolver inmediatamente su resultado (es decir, una función asíncrona) y devuelve la promesa de que tendrá el resultado en un futuro (a lo que llamo cumplir la promesa :P). A nivel de implementación, una función devuelve un objeto Promise que gestionará por ella el callback. Veamos cómo soluciona nuestros problemas:

1 – Claridad en los métodos

La función solo debe recibir la información necesaria para hacer la petición y devuelve la promesa de que esos datos llegarán.

var dir = new Directory('file:///home/user/Desktop');
var promise = dir.browse();
promise.then(function(dir, items) {
  // ...
});

Y ésto aún lo podríamos mejorar llamando directamente a la función then sin guardar el promise en una variable:

var dir = new Directory('file:///home/user/Desktop');
dir.browse().then(function(dir, items) {
  // ...
});

Y muchos dirán ¿qué diferencia hay entre ésto y el código que teníamos antes? Es sencillo, la diferencia está en quién maneja el callback. Con el código anterior cada función debía encargarse de comprobar si se le había pasado un callback válido y llamarlo al acabar su tarea con los argumentos necesarios. Ahora todo ése código está en la clase Promise y la función puede encargarse de aquello que le corresponde siempre que devuelva un promise y le notifique cuando termine. Finalmente la API queda bastante más clara:

Promise<Array<File>> Directory.browse();
Promise<String> File.getContent(String encoding);
Promise<Boolean> File.getPermission();

2 – Llamadas secuenciales

El promise trae una sorpresa que no me esperaba, el método then de la clase Promise devuelve un nuevo promise. Para qué? para poder ejecutar código secuencialmente, veamoslo:

var file = new File();
file.isReadable()
  .then(function(permission) {
    if (permission) {
      return file.getContent();
    }
})
.then(function(content) {
  // do something with the content
});

Qué es ésta locura? La idea es muy sencilla, pero es confusa porque la explicación utiliza demasiadas veces la palabra Promise, primero expandiremos el código para verlo más claro:

var file = new File();
var promise1 = file.isReadable();

var promise2 = promise1.then(function(permission) {
  if (permission) {
    var promise3 = file.getContent();
    return promise3;
  }
});

promise2.then(function(content) {
  // do something with the content
});

Debemos intentar seguirlo poco a poco, la llamada a llamada file.isReadable() nos devuelve promise1, y cuando llamamos al método then de promise1 nos devuelve promise2. Cuando promise1 termina se ejecuta el callback pasado y se descubre que el callback devuelve un nuevo Promise, promise3. Cuando promise3 se cumpla (es decir pase a estado «done») también se cumplirá el promise2 ejecutando el callback que le han pasado. En resumen, podemos seguir añadiendo callbacks que se ejecutarán al acabar el anterior encadenando llamadas a then.

3 – Llamadas paralelas

Además me planteé añadir la posibilidad de manejar llamadas paralelas desde Promise, puesto que ya hemos visto lo complejo que puede ser. Para ésto añadí el método and al Promise:

File.get('http://www.somedomain.com/file1')
  .and(File.get('http://www.somedomain.com/file2'))
  .then(function() {
    // Both files loaded.
  });

Una vez más expandamos el código para ver más claramente que está sucediendo:

var promise1 = File.get('http://www.somedomain.com/file1');
var promise2 = File.get('http://www.somedomain.com/file2');
var promise3 = promise1.and(promise2);
promise3.then(function() {
  // Both files loaded.
});

Al expandirlo es más fácil ver lo que sucede, todo Promise tiene un método and al que se le pasa otro Promise, y ésto devuelve un nuevo Promise que se cumplirá cuando los dos primeros estén cumplidos.

4 – Callbacks específicos

Finalmente el patrón Promise también trae una mejora al problema de la gestión de errores, aún no lo he mencionado pero el método then recibe dos argumentos: el primero el callback que será llamado cuando el Promise se cumpla, el segundo otro callback que será llamado si la ejecución asíncrona falla:

File.get('http://www.somedomain.com/file2').then(function(file) {
  // do something with file.
}, function(error) {
  // Show blue screen of death
});

Esto nos permite separar claramente la responsabilidad de cada función y nos libera de la carga de comprobar errores.

CONCLUSION

Como vemos las llamadas secuenciales traen muchos inconvenientes, pero son principalmente consecuencias de no estar acostumbrados a la programación asíncrona, si lo estuviéramos tendríamos más en mente patrones como Promise que como vemos nos ayuda a afrontar una programación que ya de por sí es complicada. En próximos posts espero mostrar paso la implementación de una clase Promise, nos vemos en la próxima.

166 thoughts on “El patrón Promise

  1. muy buen aporte, solo una pregunta como podría aserle para realizar peticiones en cola al servidor y que cuando termine continué la siguiente petición siempre y cuando la anterior hay terminado exitosamente, espero puedas ayudarme y gracias.

    1. Buenas Raúl,

      En realidad con promises es bastante sencillo:

      primeraPetición().then(function(primeraRespuesta) {
        return segundaPetición();
      }).then(function(segundaRespuesta) {
        return terceraPetición();
      }).then(function(terceraRespuesta) {
        return cuartaPetición();
      // ...
      }).catch(function(error) {
        // si cualquier petición falla vienes aquí
        console.error(error);
      });
      
  2. Hi, I think your site might be having browser compatibility issues. When I look at your blog site in Safari, it looks fine but when opening in Internet Explorer, it has some overlapping. I just wanted to give you a quick heads up! Other then that, amazing blog!

  3. Greetings from Florida! I’m bored at work so I decided to check out your website on my iphone during lunch break. I enjoy the information you present here and can’t wait to take a look when I get home. I’m surprised at how quick your blog loaded on my phone .. I’m not even using WIFI, just 3G .. Anyhow, good blog!

  4. Howdy! I know this is kinda off topic but I was wondering if you knew where I could find a captcha plugin for my comment form? I’m using the same blog platform as yours and I’m having problems finding one? Thanks a lot!

  5. I really like your blog.. very nice colors & theme. Did you create this website yourself or did you hire someone to do it for you? Plz respond as I’m looking to construct my own blog and would like to know where u got this from. thanks

  6. Hey there! I know this is kind of off topic but I was wondering if you knew where I could find a captcha plugin for my comment form? I’m using the same blog platform as yours and I’m having difficulty finding one? Thanks a lot!

  7. I love your blog.. very nice colors & theme. Did you create this website yourself or did you hire someone to do it for you? Plz answer back as I’m looking to construct my own blog and would like to know where u got this from. cheers

  8. Thanks for ones marvelous posting! I seriously enjoyed reading it, you happen to be a great author.I will be sure to bookmark your blog and will eventually come back down the road. I want to encourage you to definitely continue your great work, have a nice holiday weekend!

  9. Hello would you mind sharing which blog platform you’re working with? I’m going to start my own blog soon but I’m having a hard time choosing between BlogEngine/Wordpress/B2evolution and Drupal. The reason I ask is because your design and style seems different then most blogs and I’m looking for something unique. P.S Apologies for getting off-topic but I had to ask!

  10. Hi! Quick question that’s entirely off topic. Do you know how to make your site mobile friendly? My web site looks weird when viewing from my iphone. I’m trying to find a template or plugin that might be able to fix this issue. If you have any recommendations, please share. Many thanks!

  11. Howdy! Do you know if they make any plugins to assist with SEO? I’m trying to get my blog to rank for some targeted keywords but I’m not seeing very good gains. If you know of any please share. Cheers!

  12. Hello! Someone in my Facebook group shared this site with us so I came to give it a look. I’m definitely loving the information. I’m bookmarking and will be tweeting this to my followers! Terrific blog and amazing design and style.

  13. Do you mind if I quote a couple of your posts as long as I provide credit and sources back to your site? My website is in the exact same niche as yours and my visitors would truly benefit from a lot of the information you provide here. Please let me know if this okay with you. Thanks!

  14. Have you ever thought about creating an ebook or guest authoring on other websites? I have a blog based on the same subjects you discuss and would really like to have you share some stories/information. I know my readers would value your work. If you’re even remotely interested, feel free to send me an email.

  15. Hello would you mind stating which blog platform you’re working with? I’m planning to start my own blog in the near future but I’m having a tough time deciding between BlogEngine/Wordpress/B2evolution and Drupal. The reason I ask is because your layout seems different then most blogs and I’m looking for something completely unique. P.S My apologies for getting off-topic but I had to ask!

  16. Today, while I was at work, my cousin stole my iphone and tested to see if it can survive a forty foot drop, just so she can be a youtube sensation. My apple ipad is now destroyed and she has 83 views. I know this is totally off topic but I had to share it with someone!

  17. When I originally commented I clicked the «Notify me when new comments are added» checkbox and now each time a comment is added I get four emails with the same comment. Is there any way you can remove people from that service? Cheers!

  18. Hey! Someone in my Myspace group shared this website with us so I came to give it a look. I’m definitely enjoying the information. I’m bookmarking and will be tweeting this to my followers! Wonderful blog and great design and style.

  19. I was wondering if you ever thought of changing the layout of your blog? Its very well written; I love what youve got to say. But maybe you could a little more in the way of content so people could connect with it better. Youve got an awful lot of text for only having 1 or 2 pictures. Maybe you could space it out better?

  20. Please let me know if you’re looking for a article writer for your weblog. You have some really great posts and I think I would be a good asset. If you ever want to take some of the load off, I’d absolutely love to write some articles for your blog in exchange for a link back to mine. Please send me an e-mail if interested. Regards!

  21. Hi! I just wanted to ask if you ever have any trouble with hackers? My last blog (wordpress) was hacked and I ended up losing a few months of hard work due to no data backup. Do you have any solutions to protect against hackers?

  22. Does your site have a contact page? I’m having trouble locating it but, I’d like to send you an email. I’ve got some recommendations for your blog you might be interested in hearing. Either way, great website and I look forward to seeing it develop over time.

  23. Hello! I know this is kinda off topic but I’d figured I’d ask. Would you be interested in exchanging links or maybe guest authoring a blog article or vice-versa? My website addresses a lot of the same topics as yours and I feel we could greatly benefit from each other. If you’re interested feel free to shoot me an email. I look forward to hearing from you! Great blog by the way!

  24. Write more, thats all I have to say. Literally, it seems as though you relied on the video to make your point. You clearly know what youre talking about, why throw away your intelligence on just posting videos to your weblog when you could be giving us something enlightening to read?

  25. Hey I am so happy I found your web site, I really found you by mistake, while I was browsing on Digg for something else, Nonetheless I am here now and would just like to say kudos for a fantastic post and a all round entertaining blog (I also love the theme/design), I don’t have time to read through it all at the moment but I have bookmarked it and also added in your RSS feeds, so when I have time I will be back to read more, Please do keep up the excellent job.

  26. I was wondering if you ever considered changing the layout of your blog? Its very well written; I love what youve got to say. But maybe you could a little more in the way of content so people could connect with it better. Youve got an awful lot of text for only having 1 or 2 images. Maybe you could space it out better?

  27. Hi there would you mind stating which blog platform you’re working with? I’m looking to start my own blog soon but I’m having a tough time making a decision between BlogEngine/Wordpress/B2evolution and Drupal. The reason I ask is because your design seems different then most blogs and I’m looking for something completely unique. P.S My apologies for being off-topic but I had to ask!

  28. First off I would like to say terrific blog! I had a quick question in which I’d like to ask if you do not mind. I was curious to find out how you center yourself and clear your head before writing. I’ve had difficulty clearing my mind in getting my ideas out there. I do enjoy writing however it just seems like the first 10 to 15 minutes are lost just trying to figure out how to begin. Any ideas or hints? Kudos!

  29. Hey would you mind letting me know which hosting company you’re using? I’ve loaded your blog in 3 different web browsers and I must say this blog loads a lot quicker then most. Can you recommend a good web hosting provider at a reasonable price? Thanks a lot, I appreciate it!

  30. First of all I want to say excellent blog! I had a quick question which I’d like to ask if you don’t mind. I was interested to find out how you center yourself and clear your thoughts before writing. I’ve had trouble clearing my thoughts in getting my thoughts out there. I truly do enjoy writing but it just seems like the first 10 to 15 minutes are generally wasted just trying to figure out how to begin. Any suggestions or tips? Cheers!

  31. Hi there! Someone in my Facebook group shared this site with us so I came to look it over. I’m definitely loving the information. I’m book-marking and will be tweeting this to my followers! Outstanding blog and great design.

  32. I know this if off topic but I’m looking into starting my own weblog and was curious what all is required to get setup? I’m assuming having a blog like yours would cost a pretty penny? I’m not very web savvy so I’m not 100% positive. Any recommendations or advice would be greatly appreciated. Many thanks

  33. Admiring the commitment you put into your blog and detailed information you provide. It’s good to come across a blog every once in a while that isn’t the same old rehashed information. Wonderful read! I’ve bookmarked your site and I’m including your RSS feeds to my Google account.

  34. Thank you, I have just been searching for information about this subject for ages and yours is the best I’ve discovered so far. But, what about the bottom line? Are you sure about the source?

  35. Thank you for sharing excellent information. Your website is very cool. I am impressed by the info that you?ve on this website. It reveals how nicely you understand this subject. Bookmarked this web page, will come back for more articles.

  36. Hey there. I want to to ask a little something…is this a wordpress web log as we are planning to be transferring over to WP. Additionally did you make this template all by yourself? Many thanks.

  37. Hello, i read your blog from time to time and i own a similar one and i was
    just curious if you get a lot of spam comments? If so how do you protect against
    it, any plugin or anything you can recommend? I get so much
    lately it’s driving me crazy so any assistance is very much appreciated.

  38. Thanks for another informative blog. Where else could I get that type of info written in such an ideal way? I have a project that I’m just now working on, and I have been on the look out for such information.

  39. I’m usually to running a blog and i really recognize your content. The article has actually peaks my interest. I am going to bookmark your web site and maintain checking for brand new information.

  40. I discovered your site web site on the internet and check a number of your early posts. Always keep on the very good operate. I recently extra up your Rss to my MSN News Reader. Looking for forward to reading a lot more from you afterwards!…

  41. An interesting discussion may be valued at comment. I do believe that you can write more on this topic, may possibly not certainly be a taboo subject but normally persons are too little to communicate on such topics. To another. Cheers

  42. MetroClick specializes in building completely interactive products like Photo Booth for rental or sale, Touch Screen Kiosks, Large Touch Screen Displays , Monitors, Digital Signages and experiences. With our own hardware production facility and in-house software development teams, we are able to achieve the highest level of customization and versatility for Photo Booths, Touch Screen Kiosks, Touch Screen Monitors and Digital Signage. Visit MetroClick in NYC at http://www.metroclick.com/ or , 121 Varick St, New York, NY 10013, +1 646-843-0888

  43. I just desire to notify you that I am new to blog posting and extremely enjoyed your website. Very likely I am inclined to bookmark your blog post . You really have outstanding article blog posts. Like it for expressing with us your favorite blog article

  44. I enjoy the dear information you offer to your articles. I will bookmark your site and have the kids have a look at up here generally. Im fairly positive theyre likely to be informed quite a lot of new stuff here than anyone else!

  45. Faytech North America is a touch screen Manufacturer of both monitors and pcs. They specialize in the design, development, manufacturing and marketing of Capacitive touch screen, Resistive touch screen, Industrial touch screen, IP65 touch screen, touchscreen monitors and integrated touchscreen PCs. Contact them at http://www.faytech.us, 121 Varick Street, New York, NY 10013, +1 646 205 3214

  46. It truly is nearly not possible to encounter well-updated women and men on this matter, still you appear like you fully understand what exactly you’re posting on! Appreciate It

  47. Emery EPS is a Search Engine Optimization company that provides SEO Services. Their proprietary SEO strategies help struggling websites and aspiring business owners to rank their websites higher in multiple search engines like Google , Yahoo and Bing. They provide local and gmb map ranking for businesses in Coasta Rica, New York, Los Angeles, Portland, Sacramento, Phoenix, Las Vegas, Denver, Houston, California and many other local areas. Find more at https://www.emeryeps.com.

  48. Emery EPS is a Search Engine Optimization company that provides SEO Services. Their proprietary SEO strategies help struggling websites and aspiring business owners to rank their websites higher in multiple search engines like Google , Yahoo and Bing. They provide local and gmb map ranking for businesses in Coasta Rica, New York, Los Angeles, Portland, Sacramento, Phoenix, Las Vegas, Denver, Houston, California and many other local areas. Find more at https://www.emeryeps.com.

  49. It’s a pity you don’t have a donate button! I’d most certainly donate to this fantastic blog!

    I suppose for now i’ll settle for bookmarking and adding your RSS feed to
    my Google account. I look forward to brand new
    updates and will share this site with my Facebook group.
    Chat soon!

Deja un comentario

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