在throttle函数中立即调用setTimeout()

时间:2016-09-20 09:19:39

标签: javascript ecmascript-6 settimeout throttling

所以我试图写一个调用函数,调用它时调用一个回调但在给定的时间间隔内只能达到一定的限制次数。如果达到限制,则回调将被推入队列,在该队列中,在初始间隔后调用回调。

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'

主要问题是由于某种原因,在 else块内,函数不会等待setTimeout并立即被调用。语法似乎很好,所以我很难弄清楚它被调用的原因。这是被调用后的输出:

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

您会注意到,如果您使用上面一行的结果添加allotedTime,您将获得所需的日志。谢谢你看看。

Link to repl

1 个答案:

答案 0 :(得分:0)

不确定我是否完全理解了这个问题,但根据您的期望, else间隔应该是:

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

因为调用回调后totalCalls会递增。因此,要么添加totalCalls++;作为else块的第一个语句(在setInterval()之前),要么不要求增加值(建议编号1)。