Table of contents
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:
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:
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:
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:
The
promisePool
function is defined with two parameters: an array of asynchronous functionsfunctions
and an integern
representing the pool limit.The function returns a
Promise
. It's an asynchronous function that takes advantage of theasync/await
syntax and usesPromise
for its asynchronous operations.Inside the returned
Promise
, ahelper
function is defined. This function is responsible for managing the execution of functions and the pool size.The base case of the recursion is checked: If the
index
is greater than or equal to the length offunctions
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.Inside the
helper
function, awhile
loop is used to execute functions in parallel up to the pool limitn
. It checks if there's room in the pool (inProgress < n
) and if there are more functions to execute (index < functions.length
).When the loop condition is met, the
inProgress
counter is incremented, and the current function at theindex
is executed using.then()
. When the promise of the function resolves, theinProgress
counter is decremented, and thehelper
function is called recursively. This ensures that as soon as one function completes, another function is started.Outside the
helper
function, the execution is initiated by calling thehelper
function for the first time.
Code:
/**
* @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:
Hope you find helpful, if yes then give it a like.