简体   繁体   中英

setTimeout() being called immediately in throttle function

so I'm trying to write a throttle function that when called, calls a callback but only up to a certain limit number of times in a given interval. If the limit is reached, the callback gets pushed into a queue where the callback gets called after the initial interval.

const throttle = (cb, interval, maxCalls) => {
  let calls = 0;
  const records = [];
  let totalCalls = 0;
    return (...rest) => {
        if(calls < maxCalls) {
          calls++;
          records.push(Date.now());
          totalCalls++;
          cb.apply(null, rest);
          setTimeout(() => {
            calls--;
          }, interval);
        } else {
            //cb within setTimeout being invoked immediately here
            setTimeout(() => {
              calls++;
              records.push(Date.now());
              totalCalls++;
              cb.apply(null, rest);
              //console.log(allotedTime: interval - (Date.now() - records[(totalCalls-1)-maxCalls]));
            }, interval - (Date.now() - records[(totalCalls-1)-maxCalls]));
        }
    }
}

const meow = (start, ...args) => {
  console.log(Date.now() - start, ...args);
}

const burp = throttle(meow.bind(this, Date.now()), 10000, 2);

setTimeout(() => burp('burp'), 0); // expect 2-7 'burp'
setTimeout(() => burp('burp'), 5000); // expect 5000 'burp'
setTimeout(() => burp('burp'), 6000); // expect 10000 'burp'
setTimeout(() => burp('burp'), 7000); // expect 15000 'burp'

The main problem is that for some reason, within the else block , the function isn't waiting for the setTimeout and is being called immediately. The syntax seems fine so I'm having a hard time figuring out why it's being called. This is the output after being called:

setTimeout(() => burp('burp'), 0); //6 'burp'
setTimeout(() => burp('burp'), 5000); //5001 'burp'
setTimeout(() => burp('burp'), 6000) //6001 'burp'
//allotedTime: 4005
setTimeout(() => burp('burp'), 7000); //10008 'burp'
//allotedTime: 4993

You'll notice that if you add the allotedTime with the result from the line above, you'll get the desired log. Thanks for taking a look.

Link to repl

Not sure if I understood the problem entirely, but based on your expectations, the else interval should be:

interval - (Date.now() - records[totalCalls-maxCalls]))

because totalCalls is increment once the callback is called. So, either add totalCalls++; as the first statement of the else block (before setInterval() ) or don't expect the value to be incremented (suggestion number 1).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM