async programming
async await
concurrent programming
javascript
promise handling

Starting multiple async/await functions at once and handling them separately

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

In JavaScript, running async tasks sequentially is often slower than necessary. A better pattern is starting multiple promises at once, then awaiting or handling each result according to business rules. The key is separating task kickoff from task consumption so you control concurrency and error behavior.

Start Tasks First, Await Later

await pauses the current function, so awaiting too early accidentally serializes work. Start all operations first, store promises, then await them when results are needed.

javascript
1function wait(ms, value, shouldFail = false) {
2  return new Promise((resolve, reject) => {
3    setTimeout(() => {
4      if (shouldFail) {
5        reject(new Error(`failed: ${value}`));
6      } else {
7        resolve(value);
8      }
9    }, ms);
10  });
11}
12
13async function main() {
14  const userPromise = wait(300, "user");
15  const ordersPromise = wait(500, "orders");
16  const settingsPromise = wait(200, "settings");
17
18  const settings = await settingsPromise;
19  console.log("settings ready", settings);
20
21  const user = await userPromise;
22  console.log("user ready", user);
23
24  const orders = await ordersPromise;
25  console.log("orders ready", orders);
26}
27
28main().catch(console.error);

Even though results are consumed at different times, all requests started immediately.

Handling Results Separately

If each task has independent fallback logic, use individual try and catch blocks.

javascript
1async function loadDashboard() {
2  const profilePromise = fetch("https://example.com/api/profile").then(r => r.json());
3  const metricsPromise = fetch("https://example.com/api/metrics").then(r => r.json());
4  const alertsPromise = fetch("https://example.com/api/alerts").then(r => r.json());
5
6  let profile = null;
7  let metrics = [];
8  let alerts = [];
9
10  try {
11    profile = await profilePromise;
12  } catch (err) {
13    console.error("profile failed", err);
14  }
15
16  try {
17    metrics = await metricsPromise;
18  } catch (err) {
19    console.error("metrics failed", err);
20  }
21
22  try {
23    alerts = await alertsPromise;
24  } catch (err) {
25    console.error("alerts failed", err);
26  }
27
28  return { profile, metrics, alerts };
29}

This pattern avoids one failure cancelling unrelated successful data.

Use Promise.allSettled for Batch Reporting

When you need complete success and failure information together, Promise.allSettled is cleaner.

javascript
1async function runBatch() {
2  const tasks = [
3    wait(100, "A"),
4    wait(150, "B", true),
5    wait(80, "C")
6  ];
7
8  const results = await Promise.allSettled(tasks);
9
10  for (const result of results) {
11    if (result.status === "fulfilled") {
12      console.log("ok", result.value);
13    } else {
14      console.log("error", result.reason.message);
15    }
16  }
17}
18
19runBatch().catch(console.error);

allSettled is ideal for jobs where partial completion is acceptable.

Concurrency Limits

Starting everything at once can overload APIs or local resources. Use a small worker pool when tasks are numerous.

javascript
1async function mapWithConcurrency(items, limit, worker) {
2  const results = new Array(items.length);
3  let index = 0;
4
5  async function run() {
6    while (index < items.length) {
7      const current = index++;
8      results[current] = await worker(items[current], current);
9    }
10  }
11
12  await Promise.all(Array.from({ length: limit }, () => run()));
13  return results;
14}
15
16(async () => {
17  const ids = [1, 2, 3, 4, 5, 6];
18  const data = await mapWithConcurrency(ids, 2, async id => {
19    await wait(100, null);
20    return `item-${id}`;
21  });
22
23  console.log(data);
24})();

This keeps throughput high without opening unlimited concurrent operations.

Cancellation and Timeouts

Long-running async operations should support cancellation and timeout boundaries. In browser and recent Node environments, AbortController is the standard approach for fetch calls.

javascript
1async function fetchWithTimeout(url, timeoutMs) {
2  const controller = new AbortController();
3  const timer = setTimeout(() => controller.abort(), timeoutMs);
4
5  try {
6    const response = await fetch(url, { signal: controller.signal });
7    return await response.text();
8  } finally {
9    clearTimeout(timer);
10  }
11}

Without timeout logic, one stalled request can block downstream awaits and degrade user experience.

Ordered Versus Fastest Consumption

Some workflows require strict output order for auditing and reproducible logs. Others should render partial data immediately as each promise resolves. Choose this behavior explicitly so your UI and observability patterns remain predictable under load.

Common Pitfalls

  • Awaiting each call immediately after starting it. Fix by creating all promises first.
  • Using Promise.all when partial success is acceptable. Fix by choosing allSettled or per-promise handling.
  • Ignoring concurrency limits for large batches. Fix by adding a worker-pool pattern.
  • Letting one rejected promise crash an unrelated workflow. Fix by isolating errors around each awaited result.
  • Forgetting cancellation and timeout control. Fix by adding AbortController and explicit timeout wrappers.

Summary

  • Kick off async work early and await results strategically.
  • Handle each promise independently when failure policies differ.
  • Use Promise.allSettled for complete batch outcome reporting.
  • Limit concurrency to protect APIs and app stability.
  • Add timeout and cancellation support for production reliability.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.