104Implement asyncMap() over an async iterable with bounded concurrency and backpressure
Problem
Implement an async generator asyncMap(source, mapper, { concurrency = 4, ordered = true } = {}). source is any iterable or async iterable (for example paginated API results or lines of a huge file). It yields await mapper(item, index) for every item.
for await (const thumbnail of asyncMap(readFiles(folder), makeThumbnail, { concurrency: 3 })) {
gallery.append(thumbnail);
}Requirements
- At most
concurrencymapper calls run at the same time. - Backpressure: pull from
sourceonly when there is room. If the consumer stops reading, the generator stops pulling. The number of items pulled but not yet yielded never exceedsconcurrency. ordered: trueyields in input order;ordered: falseyields each result as soon as it is ready.- If the consumer stops early (
breakinfor await), close the source (call itsreturn(), so itsfinallyblocks run). - If a mapper rejects or the source throws, the generator throws that error.
Try it yourself
Write your solution, run it, then submit to check it against the tests.
Press Run or ⌘ Enter to execute your code.
Step-by-step
Use source[Symbol.asyncIterator]?.() or source[Symbol.iterator](). Pulling manually with await iterator.next() is what lets you decide when to read the next item, which is the essence of backpressure.
Unlock the full solution
What's inside
- Step-by-step
- Approach
- Solution
- Complexity
- Edge cases
- Follow-up questions
- Tests
Includes 2 code listings, 5 edge cases, 4 follow-up questions.
One-time payment by UPI, card or net banking. Launch price.