Skip to content

Instantly share code, notes, and snippets.

@malash
Last active December 5, 2021 05:06
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 malash/54e1c45ed04ebe9885cfd60a44ca1376 to your computer and use it in GitHub Desktop.
Save malash/54e1c45ed04ebe9885cfd60a44ca1376 to your computer and use it in GitHub Desktop.
A tiny concurrency limiter write with Promise and async function
export class ConcurrencyLimiter {
public constructor(private limit: number = Infinity) {}
private queue: Array<() => Promise<any>> = [];
private currentConcurrency = 0;
private async executeQueue() {
while (this.queue.length && this.currentConcurrency < this.limit) {
const tasks = this.queue.splice(0, this.limit - this.currentConcurrency);
this.currentConcurrency += tasks.length;
// eslint-disable-next-line no-await-in-loop
await Promise.race(
tasks.map(task =>
task().finally(() => {
this.currentConcurrency -= 1;
}),
),
);
}
}
public async request<R>(callback: (...args: any[]) => R | Promise<R>) {
return new Promise<R>((resolve, reject) => {
this.queue.push(() => Promise.resolve(callback()).then(resolve).catch(reject));
this.executeQueue();
});
}
}
// example:
const limiter = new ConcurrencyLimiter(3);
const limitedFetch = async () => {
// only code in `limiter.request` is limited
const res = await limiter.request(async () => {
const res = await fetch();
return res;
});
const json = await res.json();
return json;
}
limitedFetch();
limitedFetch();
limitedFetch();
limitedFetch(); // run after the first 3rd fetch
limitedFetch(); // run after the first 3rd fetch
limitedFetch(); // run after the first 3rd fetch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment