FrontendPro

48Implement an asynchronous task runner with configurable concurrency

mediumAbout 35 minutesCodingpromisesconcurrencyqueuesclasses

Problem

Implement a TaskRunner class. Unlike a pool over a fixed list, tasks can be added at any time, and the concurrency can change while it runs.

  • new TaskRunner({ concurrency = 2 })
  • add(task): task is a function returning a promise (or a value). Returns a promise that settles with that task's result.
  • setConcurrency(n): change the limit. Raising it starts waiting tasks immediately; lowering it lets running tasks finish but starts no more until there is room.
  • onIdle(): a promise that resolves when nothing is running and nothing is waiting.
  • running and waiting: the current counts.
const runner = new TaskRunner({ concurrency: 2 });
const thumbnail = runner.add(() => resize(image, 200));
const preview = runner.add(() => resize(image, 800));
runner.setConcurrency(navigator.hardwareConcurrency ?? 4);
await runner.onIdle();

Requirements

  • Tasks start in the order they were added.
  • A failing task rejects only its own promise; the runner keeps going.
  • A synchronous throw in a task counts as a failure of that task.

Try it yourself

Write your solution, run it, then submit to check it against the tests.

solution.jsJavaScript

Press Run or ⌘ Enter to execute your code.

Step-by-step

Each job stores the task plus the resolve and reject of the promise that add returned. add pushes a job and calls #pump().

Unlock the full solution

What's inside

  • Step-by-step
  • Approach
  • Solution
  • Complexity
  • Edge cases
  • Follow-up questions
  • Tests

Includes 2 code listings, 4 edge cases, 4 follow-up questions.

One-time payment by UPI, card or net banking. Launch price.

All 150 answersOne payment, yours forever