Promise pool of N
Limit concurrency without external deps.
Implement a function that runs async tasks with limited concurrency — at most N tasks at once, refilling the pool as each task finishes.
The Problem
Promise.all runs everything at once. For a list of 1000 API calls, that’s 1000 simultaneous requests — you’ll either hit rate limits or overwhelm the server.
What you want: always have exactly N requests in-flight, starting the next one as soon as one finishes.
The Implementation
async function promisePool(tasks, concurrency) { const results = []; let index = 0;
async function worker() { while (index < tasks.length) { const taskIndex = index++; results[taskIndex] = await tasks[taskIndex](); } }
const workers = Array.from({ length: concurrency }, () => worker()); await Promise.all(workers); return results;}You spawn N workers. Each worker pulls the next task, runs it, then pulls another. When there are no more tasks, the worker exits. Promise.all on the workers waits until all are done.
Usage
const urls = ["https://api.example.com/1" /* ... */];const tasks = urls.map((url) => () => fetch(url).then((r) => r.json()));
const results = await promisePool(tasks, 3); // 3 concurrent fetchesWhy the Index Variable Works
The shared index variable and index++ inside the worker look like a race condition, but JavaScript is single-threaded. The index++ happens synchronously before the await. By the time the worker resumes after an await, another worker may have incremented index further — which is exactly what you want.
Why It Matters
Anywhere you process collections of async operations — image uploads, database writes, API calls — you need concurrency control. This pattern is 20 lines and has no dependencies.