Here is a potential solution that I suggest:
function executeTasks<R>(tasks: Promise<R>[], limit: number) {
let boundedLimit = Math.min(limit, tasks.length);
let results: R[] = [];
return new Promise((resolve, reject) => {
function onTaskCompletion(result: R) {
if (results.length === boundedLimit - 1) {
resolve(results.concat([result]));
} else {
results.push(result);
}
}
tasks.forEach(task => task.then(onTaskCompletion).catch(reject));
})
}
This implementation assumes that all promises in the array return the same type of result. However, you can customize it by passing in a union type, any, or void based on your specific requirements.
The main concept is for each promise to add its result to a shared array. If the current promise fulfills the conditions, the overall promise is resolved using the collective results array. The boundedLimit
variable ensures proper handling when a numeric limit is specified, such as passing in an array of 100 promises with a limit of 5.
Regarding cancellation of ES6 promises, from my understanding and research, there isn't a practical method to cancel them, so this aspect has not been addressed in the provided solution.
You may find the structure of the onTaskCompletion
function somewhat unconventional. In asynchronous code, I prefer maintaining a single path for modifying shared state to avoid potential complications.