Promise Pool

Updated on 15 July, 2025
Promise Pool header image

Problem Statement

In the given task, an array of asynchronous functions named functions and a variable n, representing the pool limit, are provided. The goal is to create and return an asynchronous function, promisePool. When executed, this function should manage the execution of all the functions from the functions array, adhering to the constraint provided by n, the pool limit. This limit specifies the maximum number of functions that can be pending execution simultaneously.

promisePool should start by executing as many functions as allowed by the pool limit and proceed to initiate the execution of new functions as soon as any of the previously started functions resolve. It should execute functions in the order they appear in the array (i.e., functions[i] followed by functions[i + 1], and so on). Once the last function's promise resolves, promisePool itself should resolve.

For different values of n, the manner in which functions are executed changes:

  • With n = 1, functions are executed one at a time in series.
  • For n = 2, two functions are executed simultaneously until one resolves, after which the next function (if available) is executed, and this pattern continues.
  • Higher values of n allow more functions to be executed simultaneously, which can speed up the process but will be constrained by the total number of functions.

It's given that none of the functions in the array will reject, implying that error handling for rejections is not necessary. The return from promisePool can essentially be any value, as completion is importantly signified by the settling of all functions' promises.

Examples

Example 1

Input:

functions = [
  () => new Promise(res => setTimeout(res, 300)),
  () => new Promise(res => setTimeout(res, 400)),
  () => new Promise(res => setTimeout(res, 200))
]
n = 2

Output:

[[300,400,500],500]

Explanation:

Three functions are passed in. They sleep for 300ms, 400ms, and 200ms respectively.
They resolve at 300ms, 400ms, and 500ms respectively. The returned promise resolves at 500ms.
At t=0, the first 2 functions are executed. The pool size limit of 2 is reached.
At t=300, the 1st function resolves, and the 3rd function is executed. Pool size is 2.
At t=400, the 2nd function resolves. There is nothing left to execute. Pool size is 1.
At t=500, the 3rd function resolves. Pool size is zero so the returned promise also resolves.

Example 2

Input:

functions = [
  () => new Promise(res => setTimeout(res, 300)),
  () => new Promise(res => setTimeout(res, 400)),
  () => new Promise(res => setTimeout(res, 200))
]
n = 5

Output:

[[300,400,200],400]

Explanation:

The three input promises resolve at 300ms, 400ms, and 200ms respectively.
The returned promise resolves at 400ms.
At t=0, all 3 functions are executed. The pool limit of 5 is never met.
At t=200, the 3rd function resolves. Pool size is 2.
At t=300, the 1st function resolves. Pool size is 1.
At t=400, the 2nd function resolves. Pool size is 0, so the returned promise also resolves.

Example 3

Input:

functions = [
  () => new Promise(res => setTimeout(res, 300)),
  () => new Promise(res => setTimeout(res, 400)),
  () => new Promise(res => setTimeout(res, 200))
]
n = 1

Output:

[[300,700,900],900]

Explanation:

The three input promises resolve at 300ms, 700ms, and 900ms respectively.
The returned promise resolves at 900ms.
At t=0, the 1st function is executed. Pool size is 1.
At t=300, the 1st function resolves and the 2nd function is executed. Pool size is 1.
At t=700, the 2nd function resolves and the 3rd function is executed. Pool size is 1.
At t=900, the 3rd function resolves. Pool size is 0 so the returned promise resolves.

Constraints

  • 0 <= functions.length <= 10
  • 1 <= n <= 10

Approach and Intuition

The handling of asynchronous functions using a controlled concurrency model will utilize concepts and operations central to promises in JavaScript. The following breakdown delivers insights on possible implementation and the intuition behind the process:

  1. Initialize tracking for active promises to ensure it doesn't exceed the pool limit n.

  2. Start the first n executions, and for every resolution, trigger the next one in the array.

  3. Recursive function or queue-based handler can be used to launch one function after another, as slots free up.

  4. Await all executions: use Promise.all or an internal counter to detect when all operations are complete.

This approach makes sure no more than n functions run concurrently, and all are processed in order, ensuring efficient execution and conformance to constraints.

Solutions

  • JavaScript
js
var asyncFunctionPool = async function(funcs, limit) {
    const executeNext = () => funcs[limit++]?.().then(executeNext);
    return Promise.all(funcs.slice(0, limit).map(func => func().then(executeNext)));
};

The provided solution describes a method to manage the execution of multiple asynchronous functions using a promise pool in JavaScript. The function asyncFunctionPool takes two parameters: funcs, an array of asynchronous functions, and limit, the maximum number of concurrent promises that should run at the same time.

The core logic of asyncFunctionPool uses a function called executeNext, which recursively calls itself whenever a promise gets resolved. This ensures that new promises are only initiated when another one in the pool completes, maintaining the concurrency limit set by limit.

The Promise.all() method is utilized to manage the array of promises initiated by the initial slicing of funcs array up to the limit. Each function in the slice is called and upon completion, triggers executeNext to handle the next promise in the queue.

This setup helps in managing resource-intensive tasks that rely on asynchronous operations by limiting the number of concurrent operations, which can also prevent overwhelming the system or hitting API usage limits. This is particularly useful for scenarios involving large-scale data operations, API requests, or file processing tasks where execution time and resource consumption need to be optimized.

Comments

No comments yet.