main
ts 31 lines 1.23 KB
Raw
1 const asap = globalThis.setImmediate || setTimeout
2 export function makeQ(parallelization=1, max=Infinity) {
3 const running = new Set<Promise<unknown>>()
4 const queued: Array<() => Promise<unknown>> = []
5 return {
6 add(toAdd: typeof queued[0]) {
7 if (queued.length >= max + parallelization - running.size) // we may have some free slots that will be used at the next tick
8 return false
9 queued.push(toAdd)
10 asap(startNextIfPossible) // avoid calling now, as it would cause nesting/stacking of jobs
11 return true
12 },
13 isWorking() { return running.size > 0 },
14 isFree() { return running.size < parallelization },
15 setMax(newMax: number) { max = newMax },
16 queueSize() { return queued.length },
17 }
18 function startNextIfPossible() {
19 while (running.size < parallelization) {
20 const job = queued.shift()
21 if (!job) break // finished
22 const working = job() // start the job
23 if (!working) continue // it was canceled
24 running.add(working)
25 working.finally(() => {
26 running.delete(working)
27 startNextIfPossible()
28 })
29 }
30 }
31 }