Throttle JavaScript function calls, but with queuing (don't discard calls)

后端 未结 3 1868
醉梦人生
醉梦人生 2021-02-08 00:02

How can a function rate-limit its calls? The calls should not be discarded if too frequent, but rather be queued up and spaced out in time, X milliseconds apart. I\'ve looked at

相关标签:
3条回答
  • 2021-02-08 00:32

    While the snippets offered by others do work (I've built a library based on them), for those who want to use well-supported modules, here are the top choices:

    • the most popular rate limiter is limiter
    • function-rate-limit has a simple API that works, and good usage stats on npmjs
    • valvelet, a newer module, claims to do an even better job by supporting promises, but hasn't gained popularity yet
    0 讨论(0)
  • 2021-02-08 00:43

    Should be rather simple without a library:

    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/

    0 讨论(0)
  • 2021-02-08 00:46

    Here is an example which carries forward this (or lets you set a custom one)

    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;
    }
    

    Now

    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
    
    0 讨论(0)
提交回复
热议问题