Promesas en serie y en paralelo en JavaScript

Publicado el 02.04.2022 a las 13:21

Promesas en serie y en paralelo en JavaScript

Promesas en serie y en paralelo en JavaScript

¿Cómo y cuando debo de usar promesas en serie o en paralelo? 🤔


Esta semana me he encontrado con un problema 😦 en uno de mis productos SaaS y era que una función en Firebase funtions a veces se ejecutaba por completo y otras no.


La función siempre comenzaba y terminaba, pero el contenido de la función a veces se ejecutaba y a veces no.


El problema era que todo el código dentro de la función era asíncrono, entonces, si el código de la función se demoraba mucho en ejecutar Firebase lo mataba porque no era consciente de que había instrucciones por ejecutar.


Como te estará imaginando, la solución al problema pasaba por convertir mi código asíncrono en síncrono.

Con async/await es facilísimo, pero hasta ahora, siempre había necesitado ejecutar una promesa tras otra porque necesitaba la respuesta de la primera para ejecutar la segunda.


En esta ocasión no era así, por lo que decidí investigar por la ejecución de promesas en paralelo (siempre obsesionado con optimizar mi código y los recursos).

¿Cuál era el caso práctivo?

Tengo un listado de clientes de un producto SaaS en un array, y tengo que consultar para cada uno de los clientes en la base de datos si sigue vigente su subscripción.

Para ello uso una función Cron Job (puedes conocer más acerca de esas funciones aquí) que cada hora ejecuta mi código.

Como entenderás no necesito esperar a terminar de leer el primer cliente para comenzar al leer el siguiente, por lo que podría hacer la lectura de los clientes en paralelo ahorrando tiempo, ya que las funciones de Firebase Functions están limitadas a 60".


Pues bien, dicho todo esto te voy a explicar qué son y cómo usar las promesas en serie y en paralelo 📋

Usar promesas en serie o secunciales 🚄🚃🚃🚃

Las promesas en serie se utilizan cuando necesitas los datos de la respuesta de la primera promesa para poder ejecutar la segunda promesa.


Imagina que quieres obtener un listado de los nombres de tus repositorios de GitHub, tendrías que hacer dos peticiones HTTP, la primera obtener tu perfil de GitHub donde encontrarás el endpoint de tus repositorios y a continuación hacer la petición HTTP a dicho endpoint.


En ese caso tienes que esperar a la respuesta de la primera petición HTTP para poder ejectuar la segunda petición.


Al código

  fetch("https://api.github.com/users/fjmduran/")
  .then( githubProfile => githubProfile.repos_url )
  .then( reposList => console.log(reposList) ) //Aquí encontrarás tus repositorios como un array de objetos JSON
  

Promesas en paralelo

Las promesas en paralelo se usan cuando no necesitas esperar la respuesta de una promesa para ejecutar la siguiente.


Tengo un documento donde un campo es un array con los identificadores de los clientes activos de un producto SaaS.

Teniendo ese array, lo que hago en una Firebase Functions es recorrerlo y hacer la consulta de cada identificador para traer todos los datos del cliente en cuestión. Como comprenderás no necesito que se haga de forma secuencial, si no que para optimizar los recursos de la Firebase Functions lo que hago es consultar los clientes en paralelo para que la función dure lo menos posible.

Al código

  const idCustomers = ["idCustomer1", "idCustomer2",...];
  const promisesCustomers=[];
  for(const idCustomer of idCustomers){
    const promise = admin
      .firestore()
      .collection(`/customers`)
      .doc(`${court.idCourt}`)
      .get();
      promisesCustomers.push(promise);
  }
  await Promise.all(promisesCustomers)
  .then((async (responds) => {
    for (const respond of responds) {
      if (!respond.exists) {
        console.log('No se ha encontrado el cliente');
        return;
      }
      const customer: CustomerInterface = respond.data();
      await checkCustomerValid(customer);
    }        
  })) 
  .catch((err) => {
    console.log('Error en la promesa', err);
  });
  

Aclarando las promesas en paralelo con un ejemplo típico 🎁

    Imagina que tenemos tres promesas:
  1. const p1 = new Promise((resolve, reject) => { setTimeout(resolve, 1000, "one"); });
  2. const p2 = new Promise((resolve, reject) => { setTimeout(resolve, 5000, "two"); });
  3. const p3 = new Promise((resolve, reject) => { setTimeout(resolve, 2000, "three"); });

Si las ejecutamos en paralelo sería:

  Promise.all([p1, p2, p3])
  .then(values => { console.log(values); }, reason => { console.log(reason) });  
  

La salida por consola será one, three, two y se ejecutará todo en 5 segundos


Si hicieramos el consumo de promesas en serie o secuencial se demoraría todo 8 segundos.


Hasta luego 🖖

Servicios

Software

IoT

Digitalización

Aplicaciones móviles

Consultoría

fjmduran.com v0.2.2