Play with the controls to see how the code works. All code is present in the page, but some scrollback may be necessary to grok everything.
# pooling / limiting promises
2 min read
Use Set to implement a Promise API that limits the number of concurrently running tasks.
# new Set()
const numbers = new Set([1, 2, 3])
function remove() {
numbers.delete(2)
}
function add() {
numbers.add(2)
}
# makeCounter()
const { count, up, down } =
makeCounter()
function makeCounter() {
let count = 0
return {
up: () => (count += 1),
down: () => (count -= 1),
count: () => count
}
}
# hold()
const pause = () =>
hold(1).then(n =>
console.log(`took ${n} seconds`)
)
function hold(n) {
return new Promise(resolve =>
setTimeout(resolve, n * 1000, n)
)
}
# makePromise()
const Log = msg => () => console.log(msg)
const [promise, resolve, reject] =
makePromise()
promise
.then(Log('then'))
.catch(Log('catch'))
.finally(Log('finally'))
function makePromise() {
let resolve
let reject
const promise = new Promise((O, X) => {
resolve = O
reject = X
})
return [promise, resolve, reject]
}
# makePromisePool()
const add = makePromisePool(2)
const run = () =>
Promise.allSettled([
add(() => hold(3).then(log)),
add(() => hold(1).then(log)),
add(() => hold(2).then(log))
]).then(() => log('done!'))
run()
function makePromisePool(limit) {
let running = 0
const pending = new Set()
return promiseMakerFn => {
const [promise, O, X] = makePromise()
promise.finally(
() => ((running -= 1), next())
)
pending.add({ promiseMakerFn, O, X })
next()
return promise
}
function next() {
Array.from(pending).every(config => {
if (running < limit) {
running += 1
pending.delete(config)
config
.promiseMakerFn()
.then(config.O, config.X)
return true
}
})
}
}