Created
March 24, 2026 10:38
-
-
Save nraynaud/1b01418c86efe3f41a3f4ad8f863ee7a to your computer and use it in GitHub Desktop.
runWithLimitedConcurrency.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * https://timtech.blog/posts/limiting-async-operations-promise-concurrency-javascript/ | |
| * @param tasks an array of async functions taking zero parameters and returning an array of the same (representing downstream work to be added to the queue) | |
| * @param CONCURRENT_WORKERS | |
| * @return {Promise<void>} | |
| */ | |
| async function runWithLimitedConcurrency (tasks, CONCURRENT_WORKERS = navigator.hardwareConcurrency) { | |
| const allDone = Promise.withResolvers() | |
| const waitingWorkers = new Set() | |
| function resumeWaitingWorkers () { | |
| // avoid messing the iterator with add/delete in the loop | |
| const waitListCopy = [...waitingWorkers] | |
| for (const worker of waitListCopy) { | |
| // let the async slip to get concurrency | |
| worker() | |
| } | |
| } | |
| function createWorker (next_, _id) { | |
| const worker = async () => { | |
| waitingWorkers.delete(worker) | |
| try { | |
| let task | |
| while ((task = next_())) { | |
| const result = await task() | |
| if (Array.isArray(result) && result.length) { | |
| tasks.push(...result) | |
| resumeWaitingWorkers() | |
| } | |
| } | |
| } catch (err) { | |
| console.log(err) | |
| console.log('logging and resuming') | |
| } | |
| waitingWorkers.add(worker) | |
| if (waitingWorkers.size === CONCURRENT_WORKERS) { | |
| allDone.resolve(undefined) | |
| } | |
| } | |
| return worker | |
| } | |
| for (let i = 0; i < CONCURRENT_WORKERS; i++) { | |
| waitingWorkers.add(createWorker(tasks.pop.bind(tasks), i)) | |
| } | |
| resumeWaitingWorkers() | |
| await allDone.promise | |
| console.log('work done') | |
| } | |
| await runWithLimitedConcurrency(pdfs.map(file => (async () => convertPDF(file, temp_dir)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment