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

Dan*_*scu 11 javascript throttling rate-limiting task-queue debouncing

一个函数如何限制其调用?如果过于频繁,则不应丢弃这些调用,而是在时间上排队并间隔开,间隔为X毫秒.我看过油门去抖动,但他们放弃了通话而不是将它们排队等待将来运行.

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

Pet*_*tah 5

没有库应该相当简单:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 感谢您的明确答复。我将其与 @PaulS. 的答案结合起来以返回有限的函数,并且我进行了更改以立即启动队列(因为 `setInterval` 首先延迟)。[这是小提琴。](http://jsfiddle.net/dandv/47cbj/) 你觉得怎么样? (2认同)

Pau*_* S. 5

这是一个继承的示例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;
}
Run Code Online (Sandbox Code Playgroud)

现在

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
Run Code Online (Sandbox Code Playgroud)

  • 我已将此答案与@Petah 使用`setInterval` 的解决方案结合起来。[这是小提琴。](http://jsfiddle.net/dandv/47cbj/) 你怎么看? (2认同)

Dan*_*scu 2

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

  • 最流行的速率限制器是limiter
  • function-rate-limit有一个简单且有效的 API,并且 npmjs 上有良好的使用统计数据
  • Valvelet是一个较新的模块,声称通过支持 Promise 可以做得更好,但尚未普及