Async Queue with Concurrency Limit
When you have hundreds of API calls but the upstream caps you at 5 in flight, naive `Promise.all` is a 429 storm waiting to happen. A concurrency-limited queue runs at most `n` tasks at once, draining a backlog as workers free up. This snippet starts with the minimal worker pool, adds per-task error isolation, then layers in cancellation and ordered results so the helper holds up in production.
445 views
14
async function runWithLimit(tasks, limit) {
const results = new Array(tasks.length);
let cursor = 0;
async function worker() {
while (cursor < tasks.length) {
const i = cursor++;
results[i] = await tasks[i]();
}
}
const workers = Array.from({ length: Math.min(limit, tasks.length) }, () => worker());
await Promise.all(workers);
return results;
}
function job(label, ms) {
return () => new Promise((r) => setTimeout(() => r(label), ms));
}
const tasks = [job('a', 20), job('b', 5), job('c', 15), job('d', 10), job('e', 5)];
runWithLimit(tasks, 2).then((rs) => console.log(rs));Spawning limit workers that each pull the next index from a shared cursor is the simplest concurrency cap. Workers are just async loops over the cursor; once the array is drained, every worker resolves and Promise.all settles. Results land in input order because each worker writes to its claimed index, not the array tail. Pick limit based on the upstream's documented cap or your own latency budget; 4 to 8 is a reasonable default for HTTP-bound work.
2 more snippets in this entry are available for premium members.
Upgrade to Premium