Skip to content
Node.js

Async Patterns

Run promises in parallel, sequentially, and with limits.

By EZ4Code Team
asyncpromiseconcurrency

Code

// Parallel with Promise.all (fails fast)
const [users, posts] = await Promise.all([
  fetch("/api/users").then(r => r.json()),
  fetch("/api/posts").then(r => r.json())
]);

// Settled (does not reject on first failure)
const results = await Promise.allSettled(tasks);
const fulfilled = results.filter(r => r.status === "fulfilled")
                          .map(r => r.value);

// Sequential
for (const id of ids) {
  await processId(id);
}

// Map with concurrency limit
async function mapLimit(items, limit, fn) {
  const results = [];
  const executing = new Set();
  for (const item of items) {
    const p = Promise.resolve().then(() => fn(item));
    results.push(p);
    executing.add(p);
    p.finally(() => executing.delete(p));
    if (executing.size >= limit) await Promise.race(executing);
  }
  return Promise.all(results);
}

// Retry with exponential backoff
async function retry(fn, attempts = 3, delay = 200) {
  for (let i = 0; i < attempts; i++) {
    try { return await fn(); }
    catch (err) {
      if (i === attempts - 1) throw err;
      await new Promise(r => setTimeout(r, delay * 2 ** i));
    }
  }
}

Explanation

Promise.all runs promises in parallel and rejects on the first failure, while Promise.allSettled waits for all to settle regardless of outcome. A concurrency limiter using Promise.race prevents overwhelming a downstream service. Retry with exponential backoff makes transient failures transparent to callers.

More Node.js Snippets