You can use a normal iterator on Promise to do that without any external lib.
Here is a simple example in TypeScript to help with understanding typing:
import axios from 'axios'
const urls = ['https://google.com', 'https://yahoo.com']
function* requests(): IterableIterator<Promise<AxiosResponse<any>>> {
for (const url of urls) {
yield axios.get(url)
}
}
async function* parallelize<T>(
it: IterableIterator<Promise<T>>,
parallelSize = 100,
): AsyncIterableIterator<T> {
const processing = new Set<Promise<T>>();
let val = it.next();
while (!val.done) {
const value = val.value;
processing.add(value);
value.then(() => processing.delete(value));
if (processing.size >= parallelSize) {
yield Promise.race(processing.values());
}
val = it.next();
}
while (processing.size) {
yield Promise.race(processing.values());
}
}
for await (const res of parallelize(requests())) {
console.log(res.config.url); // prints https://google.com and https://yahoo.com (orders depends on who completes first)
}
What is even more awesome with this approach is that it will start new requests as soon as one is done and not serialize batches of x requests. It will constantly keep x requests running.
await Promise.all(requests())it will return you an array with the resolved promises ofaxios.get()So it will run all requests in parallel, and Promise.all() resolves when every Promise inside the iterator has resolved