This is a commonly asked question in frontend interviews, which helps in cracking similar questions related to async problems.
Implement a function called parallelLimit that takes two parameters:
- tasks: An array of functions that return promises
- limit: Maximum number of tasks to run in parallel
The parallelLimit function should execute the tasks in parallel, but limit the number of concurrent tasks to a given limit.
The function should return a promise that resolves to an array of results, where each result is the resolved value of the task.
Example
const tasks = [
() => new Promise(resolve => setTimeout(() => resolve(1), 1000)),
() => new Promise(resolve => setTimeout(() => resolve(2), 500)),
() => new Promise(resolve => setTimeout(() => resolve(3), 100)),
() => new Promise(resolve => setTimeout(() => resolve(4), 800))
];
// With limit of 2 concurrent tasks
const results = await parallelLimit(tasks, 2);
console.log(results); // [2, 3, 1, 4]
Note: before jumping on to the solution, I will recommend to try this question on PrepareFrontend platform to have better understanding, rather than memorizing the solution.
PrepareFrontend
The Art of Balancing Speed and Control in JavaScript
Solving the Parallel Task Limit Problem
Ever had too many tabs open in your browser? You know how it starts — everything slows down, your laptop sounds like a jet engine, and suddenly, even refreshing a page feels like an eternity.
JavaScript, much like your browser, can struggle when too many tasks run simultaneously.
That’s where controlling concurrency comes in. In today’s post, we’ll tackle a classic problem — executing async tasks in parallel but with a limit.
Let’s say you have an array of tasks — each a function returning a promise — but you don’t want them all to start at once.
Maybe you’re making API calls and don’t want to overwhelm the server. Or maybe you’re processing files but can only handle a few at a time.
Brief Solution Overview
To solve this problem, we need to implement parallelLimit, which executes functions returning promises while ensuring that only a specified number of them run at the same time. We achieve this by maintaining a queue of tasks and processing them in controlled batches.
The key steps are:
- Start executing tasks up to the limit.
- Keep track of actively running tasks & limit the number of tasks running at a time.
- When a task completes, start the next one.
- Return a promise that resolves when all tasks finish.
Solution
// This function takes an array of tasks and a concurrency limit
function parallelLimit(tasks, limit) {
// Keep track of total tasks and completion status
const totalTasks = tasks.length;
let taskCompleted = 0;
let runningTasks = 0;
const result = [];
// Return a promise that resolves when all tasks complete
return new Promise((resolve, reject) => {
// Helper function to execute a single task
const executeTask = (task) => {
// Return early if no task or at concurrency limit
if (!task) {
return;
}
if (runningTasks >= limit) {
return;
}
// Increment running tasks counter
runningTasks++;
// Execute the task and handle result
task().then(data => {
// Store result and update counters
result.push(data);
runningTasks--;
taskCompleted++;
if (taskCompleted === totalTasks) {
// All tasks done - resolve with results
resolve(result);
} else {
// Start next task from queue
executeTask(tasks.shift());
}
}).catch(error => {
// Reject if any task fails
reject(error);
})
}
// Initially start up to 'limit' number of tasks
for (let i = 0; i < limit; i++) {
const task = tasks.shift();
executeTask(task);
}
})
}
Top comments (0)