bg

Async For Each ~ Synchronously Run a Promise on Each Element of an Array


Posted on June 23, 2023
Tricks
JavaScript

Getting Started

Let’s say you have an array, and you need to run a promise on each of its element synchronously, like this

index.js

_26
const apiList = [
_26
"https://pokeapi.co/api/v2/pokemon/1/",
_26
"https://pokeapi.co/api/v2/pokemon/2/",
_26
"https://pokeapi.co/api/v2/pokemon/3/",
_26
"https://pokeapi.co/api/v2/pokemon/4/",
_26
"https://pokeapi.co/api/v2/pokemon/5/",
_26
];
_26
_26
apiList.forEach(endpoint => {Get pokemon from https://pokeapi.co/api/v2/pokemon/1/
_26
Get pokemon from https://pokeapi.co/api/v2/pokemon/2/
_26
Get pokemon from https://pokeapi.co/api/v2/pokemon/3/
_26
Get pokemon from https://pokeapi.co/api/v2/pokemon/4/
_26
Get pokemon from https://pokeapi.co/api/v2/pokemon/5/
_26
Script finished...
_26
Pokemon: ivysaur with id: 2
_26
Pokemon: bulbasaur with id: 1
_26
Pokemon: charmeleon with id: 5
_26
Pokemon: venusaur with id: 3
_26
Pokemon: charmander with id: 4
_26
console.log(`Get pokemon from ${endpoint}`);
_26
fetch(endpoint)
_26
.then(res => res.json())
_26
.then(data => console.log(`Pokemon: ${data.name} with id: ${data.id}`));
_26
});
_26
_26
console.log("Script finished...");

When you run that script, you get this output


_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/1/
_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/2/
_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/3/
_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/4/
_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/5/
_11
Script finished...
_11
Pokemon: ivysaur with id: 2
_11
Pokemon: bulbasaur with id: 1
_11
Pokemon: charmeleon with id: 5
_11
Pokemon: venusaur with id: 3
_11
Pokemon: charmander with id: 4

Notice that, we run the promise, in this case fetch asynchronously. even though we modify the script to use async await like code below, it doesn’t matter it will give the same result

index.js

_10
apiList.forEach(async endpoint => {
_10
console.log(`Get pokemon from ${endpoint}...`);
_10
await fetch(endpoint)
_10
.then(res => res.json())
_10
.then(data => console.log(`Pokemon: ${data.name} with id: ${data.id}`));
_10
});

Still get the same output right??, now how to run it synchronously??.

Run It Synchronously

Instead using Array.forEach we can use for loop like this

index.js

_10
(async () => {
_10
for (let index = 0; index < apiList.length; index++) {
_10
console.log(`Get pokemon from ${apiList[index]}...`);
_10
await fetch(apiList[index])
_10
.then(res => res.json())
_10
.then(data => console.log(`Pokemon: ${data.name} with id: ${data.id}`));
_10
}
_10
console.log("Finished");
_10
})();

this code is the trick to run async await in top level javascript file.


_10
(async () => {
_10
// your async await code
_10
})();

you get output like this, which means it run synchronously or sequential one by one.


_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/1/...
_11
Pokemon sync: bulbasaur with id: 1
_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/2/...
_11
Pokemon sync: ivysaur with id: 2
_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/3/...
_11
Pokemon sync: venusaur with id: 3
_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/4/...
_11
Pokemon sync: charmander with id: 4
_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/5/...
_11
Pokemon sync: charmeleon with id: 5
_11
Finished

But that is not at all pretty☺

The Better Code

Okay, let’s make it better by creating a function and callback like this


_10
const asyncForEach = async (array, callback) => {
_10
for (let index = 0; index < array.length; index++) {
_10
await callback(array[index], index, array);
_10
}
_10
};

Now your script gonna look like this

index.js

_10
(async () => {
_10
await asyncForEach(apiList, async endpoint => {
_10
console.log(`Get pokemon from ${endpoint}...`);
_10
await fetch(endpoint)
_10
.then(res => res.json())
_10
.then(data => console.log(`Pokemon: ${data.name} with id: ${data.id}`));
_10
});
_10
console.log("Finished");
_10
})();

Much better, and it’s work


_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/1/...
_11
Pokemon: bulbasaur with id: 1
_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/2/...
_11
Pokemon: ivysaur with id: 2
_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/3/...
_11
Pokemon: venusaur with id: 3
_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/4/...
_11
Pokemon: charmander with id: 4
_11
Get pokemon from https://pokeapi.co/api/v2/pokemon/5/...
_11
Pokemon: charmeleon with id: 5
_11
Finished

Typescript version

Oh you need the typescript version??, here we go

index.ts

_10
const asyncForEach = async <T>(
_10
array: T[],
_10
callback: (item: T, index: number, array: T[]) => Promise<void>
_10
) => {
_10
for (let index = 0; index < array.length; index++) {
_10
await callback(array[index], index, array);
_10
}
_10
};

© Ari1009. All rights reserved.