Los que llevamos desarrollando hace años en javascript habitualmente hemos utilizado la técnica del callback
, que consiste en generar una función pasada por argumento, comúnmente llamada callback por convención, que será ejecutada cuando la acción asíncrona se ejecute.
De esta manera se han podido resolver históricamente muchos problemas de asincronía y ejecutar handlers cuando las peticiones a nuestro servidor se han completado. Esta técnica se estandarizó en todo tipo de librerías, sin embargo, con las nuevas versiones y avances a raíz de la aparición de ES6
, esta ha pasado a ser historia, apostando totalmente por las Promises.
Uno de los mayores problemas de la técnica del callback aparece cuando debes encadenar varias llamadas dependientes, en los que se ocurría el fenómeno conocido como "callback hell"
(o también conocido como Pyramid of Doom), que seguro que habéis visto en algún meme en el que aparece un personaje de Street Fighter lanzando un Hadouken sobre un código desplazado totalmente al lado derecho.
Como vemos, el resultado no es muy estilístico para el código, además de que es complicado de seguir el anidamiento de llamadas para el programador. Por ello, cuando apareció Promises, facilitó el encadenamiento de llamadas, permitiendo un código más legible y con mayor control. Las promises proveen de dos funciones resolve
y reject
que permiten devolver el resultado ya sea satisfactorio o haya ocurrido algún problema. Actualmente javascript ha evolucionado aún más con el uso de async/await
, pero no es objetivo de este post.
Actualmente, la api Promises
es la que han adoptado la mayoría de las librerías, dejando atrás el mundo callback, y clientes http como axios o fetch utilizan esta técnica. Podríamos hablar de todas las ventajas que tiene Promises, sin embargo el objetivo de este post no es centrarse en todas las ventajas de Promises. Recomiendo la lectura del siguiente artículo (https://medium.com/datafire-io/es6-promises-patterns-and-anti-patterns-bbb21a5d0918) donde se detallan patrones y anti-patrones en el uso de las Promises. Me ha parecido muy completo y la técnica de dynamic chains me ha servidor para resolver la siguiente problemática.
El problema a resolver
El objetivo de este post es hablar de una necesidad que he tenido estas semanas, que consiste en encadenar recursivamente llamadas para recorrer las páginas de un endpoint y conseguir todos los elementos. Buceando por stackoverflow me encontré con este post: https://stackoverflow.com/questions/49129245/javascript-using-fetch-and-pagination-recursive.
En esta entrada de stackoverflow se habla de la necesidad de llamar a una api de Star Wars para recuperar los planetas de la saga, pero al tratarse de una api paginada, debemos de hacer N llamadas para obtener todos los resultados. Mi necesidad era de recuperar todos los elementos de un tipo de recurso, ya que requería de todos los valores para generar html estáticos por cada recurso.
La solución
Me pregunté cuál sería la mejor opción para solucionar el problema y la respuesta a esta entrada me ayudo a resolverlo con una técnica Dynamic Chain Promises, la cual he renombrado par este post como Pagination Promise Chain. Para ello, desarrollé una pequeña función helper que me permitiera recuperar de mis apis todos los recursos de un tipo de una forma transparente.
Aquí os dejo el snippet de código que permite solucionar esta necesidad:
Como vemos, nos apoyamos en Promises y en recursividad, para encadenar las llamadas a la api hasta que no devuelva más resultados. (ojo que esto no siempre vale si el número de elementos es excesivamente alto). Además nos apoyamos además en la técnica de callback para ir ejecutando una función que vaya devolviendo en cada iteración el progreso actual de las llamadas.
Espero que os pueda resultar útil este post y que nos cuentes qué tipos de patrones o necesidades has solucionado con Promises.