Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How can I process independent requests concurrently but keep output in input order?

Quick answer

Call each asynchronous operation while mapping over the input items, then pass the resulting promises to Promise.all. It waits for the promises and gives you a result array in the same order as those promises were supplied, even if tasks finish in another order. Use sequential awaits instead when each task needs the previous task’s result. [S1]

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I have several independent requests to make for a list of items. How do I let them run concurrently without having the displayed results jump into completion order?

Geez

Map your input items to calls of the asynchronous function, then give those returned promises to Promise.all. The operations start as the map calls them; Promise.all collects their results in the order of the input promises, not the order in which the operations finish. [S1]

Here is a runnable example. The setTimeout delays stand in for requests that take different amounts of time:

const items = [
  { id: "A", delay: 300 },
  { id: "B", delay: 100 },
  { id: "C", delay: 200 }
];

function fetchItem(item) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(`Result for ${item.id}`), item.delay);
  });
}

async function main() {
  const results = await Promise.all(items.map(fetchItem));
  console.log(results);
}

main();

The output array is Result for A, Result for B, Result for C, in that order. In this example, B’s operation finishes before A’s, but that does not reorder the collected results. Real request durations vary, so treat the delays as an illustration, not a timing guarantee.

Follow-up question

Why not just await each request inside a loop? What changes about the timing?

Geez

A sequential loop waits for one operation to finish before starting the next. That is appropriate when a later operation depends on an earlier result. If the operations are independent, starting them together avoids making each one wait in turn. [S1]

For example, sequential code might look like this:

const results = [];
for (const item of items) {
  results.push(await fetchItem(item));
}

With the illustrative delays above, that loop starts A, then B, then C; each wait happens after the previous one. With Promise.all(items.map(fetchItem)), the calls are made together, and the combined wait lasts until all results are ready. Actual elapsed time depends on the operations and runtime, so avoid relying on a precise duration. Both approaches preserve input order in this example; the difference is whether the work is started together or one operation at a time.

Follow-up question

How do I make sure the result still corresponds to the right source item when I render it?

Geez

Keep the source items in a stable array and use the ordered results at matching indexes. If you need the item’s identity later, return it alongside the result rather than assuming a completion order:

const rows = await Promise.all(
  items.map(async (item) => ({
    id: item.id,
    value: await fetchItem(item)
  }))
);

console.log(rows);

Each returned object carries its own id, and the array remains aligned with items. You can then render rows in order or look up the associated identifier. This pattern is useful for ordered lists, previews, and other displays where position or identity matters. It does not establish that the requests succeeded in every situation; add error handling that fits your application.

Follow-up question

What should I check before using this pattern, and when should I keep the work sequential?

Geez

First ask whether the tasks are genuinely independent. If task B needs a value produced by task A, await A before starting B; Promise.all does not make that dependency disappear. [S1] For independent tasks, make sure the promises are created by calling the operations inside the map. Passing the function references themselves does not start those operations. [S1]

Before displaying results, confirm that the input array’s order is the order you want to preserve. If presentation order should differ, arrange the inputs deliberately or sort the completed result objects by an explicit field. The provided example uses only local placeholder items and simulated delays; it does not demonstrate a real service, request limits, or application-specific failure handling. Those details depend on the system you are connecting to.

A practical checklist

  • Confirm that each operation can run without a previous operation’s result.

  • Call the asynchronous function for each input item when creating the promises.

  • Pass the promise array to Promise.all and use its result array for ordered output.

  • Keep an identifier with each result if the display needs to associate it with a source item.

  • Choose sequential awaits when a later operation depends on an earlier result.

A few more useful answers

Does Promise.all return results in the order the requests finish?

No. Its fulfilled result array follows the order of the input promises, even when the operations finish in a different order. [S1]

Can I pass an asynchronous function directly to Promise.all?

Pass the promises produced by calling the function, such as items.map(fetchItem). Passing the functions themselves does not start the operations. [S1]

When should I use sequential awaits instead?

Use them when a later operation depends on a value from an earlier one. For independent operations, concurrent calls can avoid waiting for each one in turn. [S1]

Sources

References used for this guide.

  1. [S1] Promise.all() — JavaScript | MDN
    developer.mozilla.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work