Skip to content

Concurrency Patterns

Concurrency controls how much async work is allowed to run at the same time. @vgerbot/async provides several layers so you can apply limits where they match your workflow.

Use collection helpers when you have a fixed input collection.

import { map } from "@vgerbot/async";
const results = await map(urls, async (url) => fetch(url), { concurrency: 4 });

Use auto when tasks have dependencies but independent branches should still run together.

import { auto } from "@vgerbot/async";
const handle = auto(
{
config: async () => loadConfig(),
user: [["config"], async ({ config }) => loadUser(config)],
featureFlags: [["config"], async ({ config }) => loadFlags(config)],
},
{ concurrency: 2 },
);

Use queue when producers add tasks over time and need to wait for capacity.

import { queue } from "@vgerbot/async";
const q = queue(processJob, { concurrency: 3 });
for (const job of jobs) {
await q.onSizeLessThan(10);
q.push(job);
}
await q.onIdle();

Use PoolTaskExecutor when callers submit task functions to a shared pool.

import { PoolTaskExecutor } from "@vgerbot/async";
const pool = new PoolTaskExecutor(3);
await Promise.all([
pool.exec(loadA),
pool.exec(loadB),
pool.exec(loadC),
]);
  • Use collection helpers for one-shot collection transformations.
  • Use auto for dependency graphs.
  • Use queue for long-lived job streams and backpressure.
  • Use executors for reusable scheduling policies shared across call sites.