-1

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...
DaShaman
  • 147
  • 1
  • 11

2 Answers2

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.

Alan
  • 45,915
  • 17
  • 113
  • 134
  • Thank you for taking the time to respond! When you said, "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." How is this not doing what I want it to do? I get that it is added to the even loop... are you hinting that I shouldn't be using a closure function? I will try to think of a way to "would be to keep track of the last time that throttle(func) was invoked." Thanks for the idea. Your 3rd comment about the even loop leads me to believe I dont need the closure function – DaShaman Dec 09 '21 at 19:55
  • 1
    @DaShaman Based on your requirements for throttle, a throttled function should only allow you to execute a function at most 1-time in given period, and all other invocations should be ignored. So if you call a throttled increment function 10 times in the window, it only increments once. Instead, what you have done in your implementation is queued the functions for execution after an elapsed time. Not only that, by using `setInterval`, the function will continue to execute over and over every time the interval elapses. Hence, my comment about the function not doing what you expect. – Alan Dec 10 '21 at 18:18
0

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