Ahora que sabemos ¿Qué son las promesas?, para qué y como se usan, podemos profundizar en ellas y aprender a controlar promesas, de forma que si tenemos varias promesas, podamos saber en que momento se han cumplido todas, garantizar un cierto orden o detalles relacionados.
Promesas «desincronizadas»
Aunque desincronizadas no es exactamente la palabra ideal, nos referimos con ella a que las promesas pueden no garantizar un orden específico y variar en su ejecución, dependiendo de lo que tarden.
Por norma general, las tareas asíncronas no sabemos cuanto tardarán en responder y/o procesarse. Hay muchos factores que pueden alterar el orden de las tareas, y depende de la tarea en cuestión:
- 1️⃣ La velocidad de conexión podría alterar cuando se reciben datos externos
- 2️⃣ La velocidad de otro servidor podría alterar cuanto tarda en responder una petición
- 3️⃣ Si los datos están cacheados en el navegador, la primera vez tarda, las siguientes no
- 4️⃣ La velocidad del sistema o navegador del usuario podría hacer tardar más una tarea
Como puedes ver, existen muchos factores que pueden alterar el orden en el que se resuelven las promesas. En algunos casos, esto puede no importar, pero en otros casos, puede ser fundamental controlarlo y garantizar que el orden de las tareas siga un orden concreto.
Controlar múltiples promesas
Pongamos un ejemplo concreto:
- 1️⃣ Tenemos dos tareas (promesas) por las que debemos esperar.
- 2️⃣ La primera promesa tarda más en cumplirse que la segunda.
- 3️⃣ Una tercera promesa está pendiente de cuando se cumplen esas dos primeras tareas.
- 4️⃣ Cuando las dos primeras tareas se cumplen, se cumple la tercera promesa.
La tercera promesa es una promesa de control, es decir, una promesa que coordina varias promesas. Esta tercera promesa se cumplirá cuando se hayan cumplido todas las promesas del grupo anterior y se rechazará si alguna no se cumple.
Promesa de control
Una promesa de control es como hemos llamado a una promesa que se encarga de controlar un grupo de promesas para coordinarlas. Imaginemos el siguiente supuesto: tenemos un grupo de tres tareas asíncronas y queremos realizar una tarea cuando las tres estén resueltas.
Quizás nuestra primera aproximación sería la siguiente:
- 1️⃣ Guardar cada tarea asíncrona en una variable (cada una es una promesa)
- 2️⃣ Crear un array con cada una de esas tres promesas.
- 3️⃣ Recorrer el array de promesas con un
.map()
haciendo unawait
- 2️⃣ El nuevo array tendría las promesas ya resueltas
El código sería algo similar a esto:
const task1 = fetch("/robots.txt"); // fetch devuelve una promise
const task2 = fetch("/theme.css"); // fetch devuelve una promise
const task3 = fetch("/index.js"); // fetch devuelve una promise
const tasks = [task1, task2, task3]; // Array de promises
// Recorrer el array de promesas para resolverlas con await
// y obtener un array derivado (map) con los datos resueltos
const responses = tasks.map(async (promise) => {
return await promise
});
El planteamiento anterior es correcto, sin embargo existe un problema inesperado. El problema es que la función .map()
(u otras array functions) no esperan a que las promesas se resuelvan, por lo que este planteamiento no nos sirve.
Si ejecutamos el código anterior, veremos como la constante
responses
en lugar de un array de respuestas delfetch()
donde se han eliminado las promesas (como probablemente esperábamos), tendrá un array de promesas. Es decir, lo mismo que teníamos inicialmente entasks
.
Así pues, para solucionar este problema podemos tomar tres aproximaciones:
Aproximación | Descripción | Más info |
---|---|---|
Utilizar for tradicionales | Usar bucles tradicionales para recorrer el array de promesas. | El map() y el async/await |
Utilizar control de promesas | La API Promise de Javascript, permite controlar promesas. | Control de promesas en grupo |