定时承诺队列/油门 [英] Timed promise queue / throttle
问题描述
我有一个请求承诺功能,它向API发出请求。我受这个API的限制,我不断收到错误消息:
I have a request-promise function that makes a request to an API. I'm rate-limited by this API and I keep getting the error message:
Exceeded 2 calls per second for api client. Reduce request rates to resume uninterrupted service.
我正在运行几个 Promise.each
并行循环,这是导致问题,如果我只运行一个 Promise.each
一切正常。在这些 Promise.each中
调用它们与请求承诺<相同的功能a / a>打电话。我想用另一个队列
函数包装此函数,并将间隔设置为 500
毫秒,以便请求
不是在彼此之后,或并行,但在队列中设置为该时间。事情是,即使需要相当长的时间来获得回复,我仍然需要这些承诺来获取他们的内容。
I'm running a couple of Promise.each
loops in parallel which is causing the issue, if I run just one instance of Promise.each
everything runs fine. Within these Promise.each
calls they lead to the same function a with a request-promise call. I want to wrap this function with another queue
function and set the interval to 500
milliseconds so that a request
isn't made after one another, or parallel, but set to that time, on queue. The thing is I still need these promises to get their contents even if it takes a rather long time to get a response.
有什么能为我做到这一点吗?我可以包装一个函数,它会以一个设定的间隔而不是并行响应或者一个接一个地激活函数吗?
Is there anything that will do this for me? Something I can wrap a function in and it will respond at a set interval and not in parallel or fire functions one after another?
更新:也许它确实需要特定的承诺,我试图使用下划线的油门功能
Update: Perhaps it does need to be promise specific, I tried to use underscore's throttle function
var debug = require("debug")("throttle")
var _ = require("underscore")
var request = require("request-promise")
function requestSite(){
debug("request started")
function throttleRequest(){
return request({
"url": "https://www.google.com"
}).then(function(response){
debug("request finished")
})
}
return _.throttle(throttleRequest, 100)
}
requestSite()
requestSite()
requestSite()
我得到的就是:
$ DEBUG=* node throttle.js
throttle request started +0ms
throttle request started +2ms
throttle request started +0ms
推荐答案
更新
最后的答案是错误的,这有效,但我仍然认为我可以做得更好:
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);
所以你需要制作请求节流功能 - 广泛 - 没关系。 Promise几乎内置排队。
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;
};
现在,makeRequest呼叫将至少相隔1000毫秒。
Now makeRequest calls will be at least 1000ms apart.
jfriend指出你每秒需要两个请求而不是一个请求 - 这与第二个队列一样容易解决:
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
};
这可以推广到 n
承诺使用类似的数组
This can be generalized to n
promises using an array similarly
这篇关于定时承诺队列/油门的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!