I believe this function should do it.
export function execSome<T>(arr: Promise<T>[], limit:number) {
let boxedLimit = Math.min(limit, arr.length);
let results :T[] = [];
return new Promise((resolve, reject) => {
function onComplete(result:T) {
if (results.length === boxedLimit - 1) {
resolve(results.concat([result]));
} else {
results.push(result);
}
}
arr.forEach(promise => promise.then(onComplete).catch(reject));
})
}
This does assume that your promises all return the same type, but you can easily pass in a union type, any, or void depending on your needs.
The basic idea is for each promise to add to an array they all have access to. If the current promise is going to satisfy the requirements, go ahead and resolve the overall promise using the common results array. We need the boxedLimit
in case you pass in a number. You can use this by passing in an array of 100 promises with 5 as the limit.
To my knowledge there is no feasible way of canceling an ES6 promise so I didn't bother.
You may feel that the onComplete function is structured a bit strangely. When working with async code I prefer there to be only one code path that modifies shared state.