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
      }
    })
  }
}