限制JavaScript函数调用,但排队(不要丢弃调用)

时间:2014-04-15 00:49:39

标签: javascript task-queue throttling rate-limiting debouncing

功能如何限制其通话?如果过于频繁,则不应丢弃这些调用,而是在时间上排队并间隔开,间隔为X毫秒。我查看了throttledebounce,但他们放弃了通话,而不是将它们排队等待将来运行。

比X毫秒间隔设置process()方法的队列更好的解决方案? JS框架中是否有这样的标准实现?到目前为止,我已经查看了underscore.js - 没有。

4 个答案:

答案 0 :(得分:4)

没有图书馆应该相当简单:

var stack = [], 
    timer = null;

function process() {
    var item = stack.shift();
    // process
    if (stack.length === 0) {
        clearInterval(timer);
        timer = null;
    }
}

function queue(item) {
    stack.push(item);
    if (timer === null) {
        timer = setInterval(process, 500);
    }
}

http://jsfiddle.net/6TPed/4/

答案 1 :(得分:4)

这是一个结转this(或允许您设置自定义)的示例

function RateLimit(fn, delay, context) {
    var canInvoke = true,
        queue = [],
        timeout,
        limited = function () {
            queue.push({
                context: context || this,
                arguments: Array.prototype.slice.call(arguments)
            });
            if (canInvoke) {
                canInvoke = false;
                timeEnd();
            }
        };
    function run(context, args) {
        fn.apply(context, args);
    }
    function timeEnd() {
        var e;
        if (queue.length) {
            e = queue.splice(0, 1)[0];
            run(e.context, e.arguments);
            timeout = window.setTimeout(timeEnd, delay);
        } else
            canInvoke = true;
    }
    limited.reset = function () {
        window.clearTimeout(timeout);
        queue = [];
        canInvoke = true;
    };
    return limited;
}

现在

function foo(x) {
    console.log('hello world', x);
}
var bar = RateLimit(foo, 1e3);
bar(1); // logs: hello world 1
bar(2);
bar(3);
// undefined, bar is void
// ..
// logged: hello world 2
// ..
// logged: hello world 3

答案 2 :(得分:1)

虽然其他人提供的片段确实有效(我已经基于它们构建了library),对于那些想要使用支持良好的模块的人来说,这里是最佳选择:

  • 最受欢迎的限速器是limiter
  • function-rate-limit有一个简单的API,可以使用npmjs上的良好使用统计数据
  • valvelet,一个较新的模块,声称通过支持承诺做得更好,但尚未普及但

答案 3 :(得分:0)

我需要一个 TypeScript 版本,所以我使用了 @Dan Dascelescufiddle 并添加了类型。

如果你能改进打字,请留下评论?

function rateLimit<T>(
  fn: (...args: Array<any>) => void,
  delay: number,
  context?: T
) {
  const queue: Array<{ context: T; arguments: Array<any> }> = []
  let timer: NodeJS.Timeout | null = null

  function processQueue() {
    const item = queue.shift()

    if (item) {
      fn.apply<T, Array<any>, void>(item.context, item.arguments)
    }

    if (queue.length === 0 && timer) {
      clearInterval(timer)
      timer = null
    }
  }

  return function limited(this: T, ...args: Array<any>) {
    queue.push({
      context: context || this,
      arguments: [...args],
    })

    if (!timer) {
      processQueue() // start immediately on the first invocation
      timer = setInterval(processQueue, delay)
    }
  }
}