I have an array that I am mapping, inside the map function I am calling an asynchronous function, that is performing an asynchronous request returning a promise using request-promise
.
I am expecting the first item of the array be mapped, perform the request and then the second item repeats the same process. But that's not what is happening in this instance.
This is my function;
const fn = async() => {
const array = [0, 1, 2];
console.log('begin');
await Promise.all(array.map(item => anAsyncFunction(item)));
console.log('finished');
return;
}
anAsyncFunction
is as follows;
const anAsyncFunction = async item => {
console.log(`looping ${item}`);
const awaitingRequest = await functionWithPromise(item);
console.log(`finished looping ${item}`);
return awaitingRequest;
}
And functionWithPromise
where the request is made
const functionWithPromise = async (item) => {
console.log(`performing request for ${item}`);
return Promise.resolve(await request(`https://www.google.com/`).then(() => {
console.log(`finished performing request for ${item}`);
return item;
}));
}
From the console logs I get;
begin
looping 0
performing request for 0
looping 1
performing request for 1
looping 2
performing request for 2
finished performing request for 0
finished looping 0
finished performing request for 1
finished looping 1
finished performing request for 2
finished looping 2
finished
However, what I want is
begin
looping 0
performing request for 0
finished performing request for 0
finished looping 0
looping 1
performing request for 1
finished performing request for 1
finished looping 1
looping 2
performing request for 2
finished performing request for 2
finished looping 2
finished
I'd normally be fine with this pattern but I seem to be getting some invalid body from the request call as I may be making too many at once.
Is there a better method for what I am trying to achieve
.map()
is not async or promise aware. It just dutifully takes the value you return from its callback and stuffs it in the result array. Even though it's a promise in your case, it still just keeps on going, not waiting for that promise. And, there is nothing you can do in that regard to change the .map()
behavior. That's just the way it works.
Instead, use a for
loop and then await
your async function inside the loop and that will suspend the loop.
Your structure:
await Promise.all(array.map(item => anAsyncFunction(item)));
is running all the anAsyncFunction()
calls in parallel and then waiting for all of them to finish.
To run them sequentially, use a for
loop and await
the individual function call:
const fn = async() => {
const array = [0, 1, 2];
console.log('begin');
for (let item of array) {
await anAsyncFunction(item);
}
console.log('finished');
return;
}
This is an important thing to know that none of the array iteration methods are async aware. That includes .map()
, .filter()
, .forEach()
, etc... So, if you want to await something inside the loop in order to sequence your async operations, then use a regular for
loop which is async
aware and will pause the loop.