AniUI Academy

Map an array with async work in parallel

easyAsync & Promises+150 XPPractice

Loading a detail record for every row in a table is the canonical case: you want all the requests in flight at once, but the results lined up with the rows they came from.

Implement mapAsync(items, fn). Call fn(item, index) for every item — all of them started before any of them are awaited — and resolve with an array of the resolved values in the original index order, regardless of which finished first. An empty array resolves with an empty array. If any call rejects, reject with the reason of whichever rejected first.

Arguments

itemsArray<T>
The input array to map over.
fn(item: T, index: number) => Promise<U>
The async mapper, called with each item and its index.

Returns

Promise<Array<U>> — A promise that resolves with the mapped values in input order. Rejects with the first rejection reason.

Examples

const results = await mapAsync([1, 2, 3], (n) =>
  new Promise((resolve) => setTimeout(() => resolve(n * 2), (4 - n) * 10))
);
// results === [2, 4, 6] — in input order, even though 3 finishes first

All three run concurrently; output order matches input.

const results = await mapAsync(["a", "b"], async (value, index) => value + index);
// results === ["a0", "b1"]

Index is passed as the second argument.

What it has to do

  • Start every call before awaiting any of them.
  • Resolve with values in input order, not completion order.
  • Pass the item's index to fn as the second argument.
  • Resolve with [] for an empty input array.
  • Reject with the first rejection reason.

Notes

  • items.map(async fn) returns an array of promises — wrap in Promise.all to get back values.
  • An empty array resolves with [] without ever calling fn.

Stuck? The javascript course covers everything this challenge needs.

Try it yourself
Loading playground...
5 tests · +150 XP

Discussion

Sign in to post
Sign in to join the conversation.Sign in

No comments yet. Be the first to say something.