/** * Concurrently run an asynchronous function on a list of items given a * concurrency limit. A concurrency limit equal to Infinity makes this function * behave like `Promise.all`. * * @params items - List of items to process * @params run - Asynchronous function to run for each item * @params concurrency - Maximum number of concurrent executions * @return A Promise that resolves to an array of results */ async function concurrent( items: Iterable, run: (item: Item, index: number) => Promise, concurrency: number = Infinity ): Promise { const pool: (() => void)[] = [] concurrency = Math.max(1, Math.floor(concurrency || 0)) return Promise.all([...items].map((item, index) => ( new Promise((resolve, reject) => { const start = () => run(item, index) .then((result) => { pool.pop()?.(), resolve(result) }) .catch((error) => { pool.splice(0), reject(error) }) index < concurrency ? start() : pool.unshift(start) }) ))) }