Timed promise queue / throttle

流过昼夜 提交于 2019-11-29 11:01:05

Update

The last answer was wrong, this works but I still think I can do better:

// call fn at most count times per delay.
const debounce = function (fn, delay, count) {
    let working = 0, queue = [];
    function work() {
        if ((queue.length === 0) || (working === count)) return;
        working++;
        Promise.delay(delay).tap(() => working--).then(work);
        let {context, args, resolve} = queue.shift();
        resolve(fn.apply(context, args));
    }
    return function debounced() {
        return new Promise(resolve => {
            queue.push({context: this, args: arguments, resolve});
            if (working < count) work();
        });
    };
};

function mockRequest() {
    console.log("making request");
    return Promise.delay(Math.random() * 100);
}

var bounced = debounce(mockRequest, 800, 5);
for (var i = 0; i < 5; i++) bounced();
setTimeout(function(){
    for (var i = 0; i < 20; i++) bounced();
},2000);

So you need to make the requests throttle function-wide - that's fine. Promises have queueing pretty much built in.

var p = Promise.resolve(); // our queue

function makeRequest(){
    p = p.then(function(){ // queue the promise, wait for the queue
        return request("http://www.google.com");
    });
    var p2 = p; // get a local reference to the promise
    // add 1000 ms delay to queue so the next caller has to wait 
    p = p.delay(1000); 
    return p2;
};

Now makeRequest calls will be at least 1000ms apart.

jfriend has pointed out that you need two requests per second and not a single one - this is just as easily solvable with a second queue:

var p = Promise.resolve(1); // our first queue
var p2 = Promise.resolve(2); // our second queue

function makeRequest(){

    var turn = Promise.any([p, p2]).then(function(val){ 

        // add 1000 ms delay to queue so the next caller has to wait 
        // here we wait for the request too although that's not really needed, 
        // check both options out and decide which works better in your case
        if(val === 1){
            p = p.return(turn).delay(1, 1000);
        } else {
            p2 = p2.return(turn).delay(1, 1000); 
        }
        return request("http://www.google.com");
    });

    return turn; // return the actual promise
};

This can be generalized to n promises using an array similarly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!