Skip to content

Instantly share code, notes, and snippets.

@james4388
Created July 20, 2021 06:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save james4388/371503a5bd67aeb4cf5cb26467974752 to your computer and use it in GitHub Desktop.
Save james4388/371503a5bd67aeb4cf5cb26467974752 to your computer and use it in GitHub Desktop.
Map in parallel and only allow to run with concurrencyLimit
type InputWithIndex<I> = [I, number];
async function parallelMap<I, O>(inputs: I[], asyncMapper: (...input: I[]) => O, concurrencyLimit: number = 5): Promise<O[]> {
concurrencyLimit = Math.max(1, concurrencyLimit);
const inputStack: InputWithIndex<I>[] = inputs.map((input: I, index: number): InputWithIndex<I> => [input, index]).reverse();
const results = new Array(inputs.length).fill(undefined);
const workers = new Array(concurrencyLimit).fill(undefined);
async function work() {
if (inputStack.length) {
const [input, originalIndex]: InputWithIndex<I> = inputStack.pop();
let result;
if (Array.isArray(input)) {
result = await asyncMapper(...input);
} else {
result = await asyncMapper(input);
}
results[originalIndex] = result;
return work();
}
return Promise.resolve();
}
await Promise.all(workers.map(work));
return results;
}
// Test code;
let counter = 0;
let interval = 0;
async function doulbeMapper(input: number) {
return new Promise((resolve, reject) => {
counter += 1;
setTimeout(() => {
counter -= 1;
resolve(input * 2);
}, Math.random() * 3000);
})
}
const watchCounter = () => {
console.log('Promises running in the beginning:', counter);
if (interval) {
clearInterval(interval);
}
interval = setInterval(() => console.log('Promises running:', counter), 1000);
};
(async () => {
watchCounter();
const arr = await parallelMap([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17], doulbeMapper, 4);
console.log(arr);
clearInterval(interval);
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment