Reputation: 7470
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
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
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
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