JS Tip: #1 - async/await sobre arrays
DevJoseManuel
Posted on May 3, 2022
Supongamos que, por la razón que sea, estamos recorriendo un array con el método map()
y que tenemos que ejecutar una función asíncrona en cada uno de los elementos. Algo como lo siguiente:
const users = ['user1', 'user2', 'user3']
const data = users.map(async (user) => await fetchApiData(user))
lo que tenemos que entender aquí es que la función ficticia fetchApiData
(la cual recibe como parámetro el nombre de uno de un usuario) estará realizando una llamada asíncrona a una API externa con la que trabaja nuestra aplicación.
¿Qué ocurre si ahora a continuación escribimos el contenido de la variable data
por la consola? Pues que nos vamos a encontrar con algo como lo siguiente:
const users = ['user1', 'user2', 'user3']
const data = users.map(async (user) => await fetchApiData(user))
console.log(data)
/*
[
Promise { <pending> },
Promise { <pending> },
Promise { <pending> }
]
*/
Es decir, que la ejecución del código no se para a la espera de recibir los resultados de la llamada a la API externa y por lo tanto el array data estará formado por tantos elementos como usuarios hemos declarado en el array users
y asociados a cada una de las posiciones un objeto Promise
de JavaScript en el estado pending.
Resolución de todas las llamadas en paralelo.
La primera de las opciones que tenemos para poder solucionar este problema pasa por utilizar el método all()
del objeto Promise
de JavaScript el cual va a permitir que todas las promesas que recibe como parámetro (este método espera recibir como parámetro un array de promesas que se deben resolver) pasan a ser ejecutadas en paralelo, sin depender unas de otras, y no finaliza su ejecución hasta que todas estas promesas hayan finalizado.
const users = ['user1', 'user2', 'user3']
const data = await Promise.all(
users.map(async (user) => await fetchApiData(user))
)
console.log(data)
/*
[
dataFromUser1,
dataFromUser2,
dataFromUser3
]
*/
Al ejecutarse en paralelo tenemos que entender que el tiempo de ejecución total del método será el de la promesa que consume más tiempo de resolucíón, lo cual lo hace una alternativa muy rápida cuando no hay una dependencia entre promesas.
Resolución de las llamas de forma secuencial.
Pero ¿qué ocurrirá en el caso de que tengamos una dependencia en la ejecución de las promesas, es decir, que las llamadas a la función asíncrona (en nuestro ejemplo la API externa dependerán del resultado de la llamada anterior)? Es este caso deberemos utilizar la estructura for ... of
como sigue:
const users = ['user1', 'user2', 'user3']
const data = []
for (const user of users) {
data.push(await fetchApiData(user))
}
console.log(data)
/*
[
dataFromUser1,
dataFromUser2,
dataFromUser3
]
*/
En este caso es fácil entender que, como una llamada depende de la anterior, el resultado de la ejecución de todo el código será la suma de la resolución de cada una de las promesas por separado.
Posted on May 3, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.