theJuls
theJuls

Reputation: 7470

Doing an async operation on each item while doing a "double iteration" on an array

Don't know if the terminology is correct, but I have an array of objects, which also has other arrays in it. I need to go through each of these items. If the operation wasn't async it would look something like this:

myArray.forEach(x => {
  x.otherArray.forEach(y => {
    doSomething(y)
  })
})

However the doSomething function is async, and unfortunately I am well aware that during these iterations I can't simply through a couple asyncs and awaits to make it work.

Usually, when I need to do promises during a iteration, I do the following:

await myArray.reduce((p, item) => {
  return p.then(() => {
    return doAsyncSomething(item)
  })
}, Promise.resolve())

But because I am doing two iterations at once, this becomes a bit more complicated, so how do I go about it?

I currently have something like this, but it doesn't seem to be the right way:

await myArray.reduce((p, item) => {
    return item.someArray.reduce((promise, it, index) => {
      return promise.then(() => {
        return doAsyncSomething()
      })
    }, Promise.resolve())
  }, Promise.resolve())

I know I could just organize my objects into an array through the two forEach and then do the reduce with the doSomething in it, but I doubt it's the most efficient or elegant way of getting it done. So how could I do this?

Upvotes: 2

Views: 73

Answers (3)

tdjprog
tdjprog

Reputation: 719

try this:

let objArray = [ {otherArray: [1,2]}, {otherArray: [3,4]}, {otherArray: [5,6]} ];

function doAsyncSomething(item) {
    return Promise.resolve(item);
}

async function doit() {
    let s = 0;
    for(const x of objArray)
        for(const y of x.otherArray)
            s+= await doAsyncSomething(y);

    return s;
}

doit().then(v => {
  console.log(v);
});

or try recurcive call like this:

let objArray = [ {otherArray: [1,2]}, {otherArray: [3,4]}, {otherArray: [5,6]} ];
let index = 0;
let subIndex = 0;

function doAsyncSomething(item) {
    return new Promise(resolve => {
        console.log("proc item", item);
        resolve(item);
    });
}

async function doit() {
    return await doAsyncSomething(objArray[index].otherArray[subIndex]);
}

function go() {
    doit().then(v => {
        console.log(v);

        subIndex++;
        if (subIndex >= objArray[index].otherArray.length) {
            subIndex = 0;
            index++;
        }
        if (index < objArray.length)
            go();
    });
}

Upvotes: 2

Jonas Wilms
Jonas Wilms

Reputation: 138417

Pass on the promise into the inner loop when reducing:

  await myArray.reduce((p, item) =>
    item.someArray.reduce((p, it, index) => 
      p.then(() => doAsyncSomething(it)),
      p // <<<
    ), 
    Promise.resolve()
  )

Or I'd prefer:

  for(const { someArray } of myArray) {
    for(const it of someArray) {
       await doSomethingAsync(it);
    }
 }

If you want to run the tasks in parallel:

  await Promise.all(
    myArray.flatMap(item => item.someArray.map(doSomethingAsnyc))
 );

Upvotes: 0

slebetman
slebetman

Reputation: 113964

Assuming you want all operations to happen in parallel, you can use Promise.all():

async function () { // I assume you already have this

  // ...

  let asyncOps = [];

  myArray.forEach(x => {
    x.otherArray.forEach(y => {
      asyncOps.push(doSomething(y));
    })
  })

  await Promise.all(asyncOps);
}

function doSomething (x) {
    return new Promise((ok,fail) => 
        setTimeout(() => {
            console.log(x);
            ok();
        },10));
}

let foo = [[1,2,3,4],[5,6,7,8]];

async function test() {
    let asyncOps = [];
    foo.forEach(x => 
        x.forEach(y => 
            asyncOps.push(doSomething(y))));
    
    await Promise.all(asyncOps);
}

test();

If you want to do the async operations sequentially it's even simpler:

async function () { // I assume you already have this

  // ...

  for (let i=0; i<myArray.length; i++) {
    let x = myArray[i];
    for (let j=0; j<x.length; j++) {
      let y = x[j];

      await doSomething(y);

    }
  }
}

Upvotes: 0

Related Questions