Delay Batch GET Requests To Server, JavaScript
Solution 1:
The problem with your code is that you only call the fulfil
method of the first promise in getUrl
, but call that many times. The promise will be resolved when the first call to fulfil
occurs, subsequent calls will be ignored.
Using a chained promise queue is a simple way to schedule the calls:
function delay(ms, val) {
return new Promise(resolve => {
setTimeout(() => {
resolve(val);
}, ms);
});
}
class Scheduler {
constructor(interval) {
this.queue = Promise.resolve();
this.interval = interval;
}
submit(fn) {
const result = this.queue.then(fn);
this.queue = this.queue.then(() => delay(this.interval));
return result;
}
wrapFn(fn) {
const _this = this;
return function() {
const targetThis = this, targetArgs = arguments;
console.log("Submitted " + arguments[0]); // for demonstration
return _this.submit(() => fn.apply(targetThis, targetArgs));
}
}
}
function mockGet(url) {
console.log("Getting " + url);
return delay(100, "Resolved " + url);
}
const scheduler = new Scheduler(500);
const getUrl = scheduler.wrapFn(mockGet);
getUrl("A").then(x => console.log(x));
getUrl("B").then(x => console.log(x));
getUrl("C").then(x => console.log(x));
setTimeout(() => {
getUrl("D").then(x => console.log(x));
getUrl("E").then(x => console.log(x));
getUrl("F").then(x => console.log(x));
}, 3000);
EDIT: Above snippet was edited to wait for a constant amount of time instead of the last mockGet resolution. Although I don't really understand your goals here. If you have a single client, then you should be fine with serializing the api calls. If you hav lots of clients, then this solution will not help you, as the same amount of calls will be made in a time segment as without this throttling, just the load on your server will be spread instead of coming in bursts.
EDIT: Made the code object oriented to be simpler to modularize to meet some your clean code requirements.
Solution 2:
Solution
Delaying batch requests is exactly the same as delaying any asynchronous call. After a lot of tries and asking around, I finally came to the solution I was looking for in this question:
There is an in depth explanation of the reasoning and why I picked the answer I did as well.
Queue vs Math
In the answer above, I compare to solution to this problem. One using queue logic, like I was attempting to do here, and one using Math.
Usually if you have a mathematic expression you end up needing less logic and the code is easier to maintain. This is the solution I picked.
// Seed our "last call at" value
let lastCall = Date.now();
let delayAsync = function(url) {
return new Promise(fulfil => {
// Delay by at least `delayMs`, but more if necessary from the last call
const now = Date.now();
const thisDelay = Math.max(delayMs, lastCall - now + 1 + delayMs);
lastCall = now + thisDelay;
setTimeout(() => {
// Fulfill our promise using the result of `asyncMock`'s promise
fulfil(asyncMock(url));
}, thisDelay);
});
};
However, since I was on the path of using queue logic, I decided to post my 2 cents as well, and I am quite proud of it.
For more information I strongly recommend you read the whole thing !
Post a Comment for "Delay Batch GET Requests To Server, JavaScript"