# Promise Pool JavaScript Leetcode 2636

Given an array of asynchronous functions `functions` and a pool limit n, return an asynchronous function promisePool. It should return a promise that resolves when all the input functions resolve.

The **Pool limit** is defined as the maximum number of promises that can be pending at once. `promisePool` should begin execution of as many functions as possible and continue executing new functions when old promises resolve. `promisePool` should execute `functions[i]` then `functions[i + 1]` then `functions[i+2]`, etc. When the last promise resolves, `promisePool` should also resolve.

For example, if `n = 1, promisePool` will execute one function at a time in a series. However, if `n = 2`, it first executes two functions. When either of the two functions resolves, a 3rd function should be executed (if available), and so on until there are no functions left to execute.

You can assume all `functions` never reject. It is acceptable for `promisePool` to return a promise that resolves any value.

### Example 1:

**Input:**

```javascript
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. The pool size is 2.

At t=400, the 2nd function resolves. There is nothing left to execute. The pool size is 1.

At t=500, the 3rd function resolves. The pool size is 0 so the returned promise also resolves.

### Example 2:

**Input:**

```javascript
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. The pool size is 2.

At t=300, the 1st function resolved. The pool size is 1.

At t=400, the 2nd function resolves. The pool size is 0, so the returned promise also resolves.

### Example 3:

**Input:**

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

**Output:** \[\[300,700,9001,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. The pool size is 1.

At t=300, the 1st function resolves and the 2nd function is executed. The pool size is 1.

At t=700, the 2nd function resolves and the 3rd function is executed. The pool size is 1.

At t=900, the 3rd function resolves. The pool size is 0 so the returned promise resolves.

Constraints:

`0 <= function.length <= 10`

`0 <= n <= 10`

### Intuition:

The problem revolves around executing a given set of asynchronous functions in a controlled manner with a specified pool limit. The goal is to execute as many functions concurrently as the pool limit allows while ensuring that the overall execution sequence follows the order of the input functions.

### **Approach:**

1. The `promisePool` function is defined with two parameters: an array of asynchronous functions `functions` and an integer `n` representing the pool limit.
    
2. The function returns a `Promise`. It's an asynchronous function that takes advantage of the `async/await` syntax and uses `Promise` for its asynchronous operations.
    
3. Inside the returned `Promise`, a `helper` function is defined. This function is responsible for managing the execution of functions and the pool size.
    
4. The base case of the recursion is checked: If the `index` is greater than or equal to the length of `functions` and there are no promises in progress (`inProgress === 0`), it means all functions have been executed. In this case, the main promise is resolved to signal the completion.
    
5. Inside the `helper` function, a `while` loop is used to execute functions in parallel up to the pool limit `n`. It checks if there's room in the pool (`inProgress < n`) and if there are more functions to execute (`index < functions.length`).
    
6. When the loop condition is met, the `inProgress` counter is incremented, and the current function at the `index` is executed using `.then()`. When the promise of the function resolves, the `inProgress` counter is decremented, and the `helper` function is called recursively. This ensures that as soon as one function completes, another function is started.
    
7. Outside the `helper` function, the execution is initiated by calling the `helper` function for the first time.
    

### Code:

```javascript
/**
 * @param {Function[]} functions
 * @param {number} n
 * @return {Function}
 */
// TC: O(functions.length)
var promisePool = async function (functions, n) {
  return new Promise((resolve) => {
    let inProgress = 0, index = 0;
    function helper() {
      // base case
      if (index >= functions.length) {
        if (inProgress === 0) resolve();
        return;
      }

      while (inProgress < n && index < functions.length) {
        inProgress++;
        functions[index++]().then(() => {
          inProgress--;
          helper();
        });
      }
    }
    helper();
  });
};

/**
 * const sleep = (t) => new Promise(res => setTimeout(res, t));
 * promisePool([() => sleep(500), () => sleep(400)], 1)
 *   .then(console.log) // After 900ms
 */
```

**Time Complexity:**

The time complexity of this code is O(functions.length), where "functions.length" represents the number of functions in the input array. This is because each function is executed once within the while loop, and the while loop iterates through all the functions in the array.

**Space Complexity:**

The space complexity of this code is O(1), which is constant space complexity. This is because the memory usage of the code does not grow with the input size or any recursion depth.

Checkout the video Solution:

%[https://www.youtube.com/watch?v=gsLvpzuheQU] 

Hope you find helpful, if yes then give it a like.
