'Trying to use setInterval to make a throttling function unsuccessfully

I am trying to return a function that only invokes a callback function 'func' once per every 'wait' milliseconds.

Additional calls to the callback 'func' within the 'wait' period should NOT be invoked or queued.

This is what I have so far...

function throttle(func, wait) {
    function inner(...args) {
        setInterval(func(...args), wait);
    }
    return inner;
}

When I run the code through the test algorithm I get the following errors:

  1. "throttled functions should only be able to be called again after the specified time"

Here is the testing algorithm...

let counter = 0;
const incr = () => counter++;
const throttledIncr = throttle(incr, 32);
throttledIncr();
throttledIncr();
setTimeout(() => {
  expect(counter).to.eql(1);
  throttledIncr();
  setTimeout(() => {
    expect(counter).to.eql(2);
    done();
  }, 32);
}, 32);
  1. "throttled functions return their value"

Here is the testing algorithm...

let counter = 0;
const incr = () => ++counter;
const throttledIncr = throttle(incr, 32);
const result = throttledIncr();
setTimeout(() => {
  expect(result).to.eql(1);
  expect(counter).to.eql(1);
  done();
}, 64);
  1. "throttled functions called repeatedly should adhere to time limitations"

Here is the testing algorithm...

const incr = () => ++counter;
const throttledIncr = throttle(incr, 64);
const results = [];
const saveResult = () => results.push(throttledIncr());
saveResult();
saveResult();
setTimeout(saveResult, 32);
setTimeout(saveResult, 80);
setTimeout(saveResult, 96);
setTimeout(saveResult, 180);
setTimeout(() => {
  expect(results[0]).to.eql(1);
  expect(results[1]).to.be(undefined);
  expect(results[2]).to.be(undefined);
  expect(results[3]).to.eql(2);
  expect(results[4]).to.be(undefined);
  expect(results[5]).to.eql(3);
  done();
}, 192);

My questions regarding each case:

  1. How do I prevent the function from being called again ?
  2. Why ISNT my function returning value? I can't deduce what or how to return a value with the given testing algorithm.
  3. What does "throttled functions called repeatedly should adhere to time limitations" even mean? This seems contradictory to the first error. There isn't any mention of setting a time limit so I don't believe using setTimeout here is what they mean...


Solution 1:[1]

How do I prevent the function from being called again ?

function throttle(func, wait) {
    function inner(...args) {
        setInterval(func(...args), wait);
    }
    return inner;
}

First, your code above does not do what you expect it to do. Currently every time you invoke throttle, you are adding func to the event loop, to be executed on an interval.

So when you call throttleIncr 5 times, you are adding incr to the eventloop to be called five times.

One approach (imo), would be to keep track of the last time that throttle(func) was invoked. The next time throttle(func) is invoked, check to see if the wait time has elapsed. If so, invoke func and save off the new time. If not, return.

Why ISNT my function returning value? I can't deduce what or how to return a value with the given testing algorithm.

Your incr function, IS returning the value, however your throttle function puts it on the eventloop, for asychronous execution, so the return value is not available.

What does "throttled functions called repeatedly should adhere to time limitations" even mean? This seems contradictory to the first error.

This is not a javascript error, and likely a custom failure message from the tests you are invoking.

Solution 2:[2]

I tried something here, that seems to be working:

function throttle2(callback, delay = 1000) {
  let interval;
  let currentArgs;
  return (...args) => {
    currentArgs = args;
    if (!interval) {
      interval = setInterval(() => {
        if (currentArgs) { 
          callback(...currentArgs);
          currentArgs = null;
        } else {
          clearInterval(interval);
          interval = false;
        }
      }, delay);
    }
  };
}

Sandbox: https://codesandbox.io/s/competent-tereshkova-ccop2e?file=/index.js:167-179

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Alan
Solution 2 Ayoub ASRI