Scotty Jamison
Scotty Jamison

Reputation: 13139

Get arguments from all calls to a throttled function (lodash)

I'm reworking some logger logic that batches writes together. This sounded like the perfect job for lodash's throttle function, but soon found out that by replacing the setTimeouts with throttle, the code was still much uglier than I would have hoped for. This code should give the basic idea (there's a little more to the functions than what's shown).

let queue = []

function write(message) {
  queue.push(message)
  scheduleFlushOfQueue()
}

const scheduleFlushOfQueue = _.throttle(function flushQueue() {
  const dataToWrite = queue.join('\n')
  queue = []
  fs.promises.appendFile(path, dataToWrite)
}, 100, { leading: false })

As you can see, I'm having to use a global queue variable in order to pass arguments from write() to scheduleFlushOfQueue() (gross 🤢). Ideally, I would want _.throttle to just pass in a list of parameters that came from all invocations so that I wouldn't have have to manage a global variable, but it doesn't do that.

I'm not very familiar with Lodash and what other kinds of functions it provides, so I thought I would reach out to the stack overflow community to see if anyone could think of a better way to write this kind of code.

Upvotes: 0

Views: 515

Answers (1)

Ori Drori
Ori Drori

Reputation: 191976

You create a closure with the queue variable using a factory function (createWriteQueue). The function creates the queue, and returns the function to handle it (scheduleFlushOfQueue, and write):

const createWriteQueue = () => {
  let queue = []

  const scheduleFlushOfQueue = _.throttle(function flushQueue() {
    const dataToWrite = queue.join('\n')
    queue = []
    console.log(dataToWrite) // fs.promises.appendFile(path, dataToWrite)
  }, 100, { leading: false })

  return {
    write(message) {
      queue.push(message)
      scheduleFlushOfQueue()
    },
    scheduleFlushOfQueue,
  }
}

const q1 = createWriteQueue()

q1.write('a')
q1.write('b')
q1.write('c')

const q2 = createWriteQueue()

q2.write('d')
q2.write('e')
q2.write('f')
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>

Another option is to create a class that does the same. Use arrow functions to bind this automatically.

class WriteQueue {
  queue = []
  
  scheduleFlushOfQueue = _.throttle(() => {
    const dataToWrite = this.queue.join('\n')
    this.queue = []
    console.log(dataToWrite) // fs.promises.appendFile(path, dataToWrite)
  }, 100, { leading: false })
  
  write = (message) => {
    this.queue.push(message)
    this.scheduleFlushOfQueue()
  }
}

const q1 = new WriteQueue()

q1.write('a')
q1.write('b')
q1.write('c')

const q2 = new WriteQueue()

q2.write('d')
q2.write('e')
q2.write('f')
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>

Upvotes: 1

Related Questions