Home > Net >  Cycling through a list with async call inside
Cycling through a list with async call inside

Time:11-22

I have an array of Ids, I need to iterate through all the Ids, and for each Ids of the array make an async call to retrieve a value from DB, then sums all the value gathered. I did something like this

  let quantity = 0;
  for (const id of [1,2,3,4]) {
    const subQuantity = await getSubQuantityById(id);
    quantity  = subQuantity;
  }

Is there a more elegant and coincise way to write this for in javascript?

CodePudding user response:

It is totally fine because your case include an async operation. Using a forEach instead is not possible here at all.

Your for loop is perfectly clean. If you want to make it shorter you could even do:

let totalQuantity = 0;
for (const id of arrayOfIds) {
  totalQuantity  = await getSubQuantityById(id);
}

As-is, it may even be more clear than using = await as above.

Naming could be improved as suggested.

I find the following one liner suggested in comments more cryptic and hence less clean:

(await Promise.all([1,2,3,4].map(i => getSubQuantityById(id))).reduce((p, c) => p   c, 0)

CodePudding user response:

Is there a more elegant and coincise way to write this for in javascript?

Certainly, by processing your input as an iterable. The solution below uses iter-ops library:

import {pipeAsync, map, wait, reduce} from 'iter-ops';

const i = pipeAsync(
    [1, 2, 3, 4], // your list of id-s
    map(getSubQuantityById), // remap ids into async requests
    wait(), // resolve requests
    reduce((a, c) => a   c) // calculate the sum
); //=> AsyncIterableExt<number>

Testing the iterable:

(async function () {
    console.log(await i.first); //=> the sum
})();

It is elegant, because you can inject more processing logic right into the iteration pipeline, and the code will remain very easy to read. Also, it is lazy-executing, initiates only when iterated.

Perhaps even more importantly, such a solution lets you control concurrency, to avoid producing too many requests against the database. And you can fine-tune concurrency, by replacing wait with waitRace.

P.S. I'm the author of iter-ops.

CodePudding user response:

I can't follow @vitaly-t's argument that concurrent database queries will cause "problems" - at least not when we are talking about simple queries and there is a "moderate" number of these queries.

Here is my version of doing the summation. Obviously, the console.log in the last .then() needs to be replaced by the actual action that needs to happen with the calculated result.

// a placeholder function for testing:
function getSubQuantityById(i){
  return fetch("https://jsonplaceholder.typicode.com/users/" i).then(r=>r.json()).then(u=> u.address.geo.lat);
}

Promise.all([1,2,3,4].map(id => getSubQuantityById(id)))
 .then(d=>d.reduce((p, c) => p   c,0))
 .then(console.log)

  • Related