I am working on the initial data pull for a project. It will be cached and further requests will be much less. I am attempting to space out my API requests every 5 seconds to avoid overloading the server and hitting the rate limit per their rules. It does not seem that my setTimeout()
function is actually working as desired. I logged time stamps to see and all iterations seem to be happening at the exact same time. I think this somehow due to the asynchronous nature of javascript, but I'm not sure how to remedy it. Any help would be greatly appreciated.
Code Excerpt:
var leagues;
function getLeagues(){
var reqURL = "url";
var data = new XMLHttpRequest();
data.open("GET", reqURL);
data.responseType = "text";
data.send();
// parse data on load
data.onload = function() {
// League IDs
leagues = JSON.parse(data.response)
for (i = 0; i < 5; i++) {
delay(i); // iterate every 5 secs
}
};
}
function delay(i) {
setTimeout(() => {
var d = new Date();
console.log(d.getSeconds())
}, 5000);
}
setTimeout
is a browser API that will guarantees not an exact delay time to execute after but a minimum time to execute a function so it's not related to js
.
setTimeout
cause the browser to set a timer after x milliseconds, when finished the function you pass will be in the event queue, but it won't necessarily execute, if event queue was completely empty, you are lucky and the function get executed immediately after 5 seconds, otherwise the function have to wait in queue until each function get executed before so we have (5 seconds + some times until the function get in the head of the queue then get executed).
calling setTimeout
five times in sequence (using a for
loop) with the same time delay will add the same function 5 consequent times in the event queue, all will be executed at the same time because of the same time delay used for all of them. so a solution would be to use different delay time for each function.
I'll suggest the solution for the same problem, because I faced it alot
Callback based solution
repeat(processingRequest, 5, 5000);
function processingRequest(){
console.log('Making request at', new Date().getTime());
}
function repeat(func, howManyTimes, milliSecondsInterval){
if(howManyTimes > 0)
delay(() => {
func();
howManyTimes--;
repeat(func, howManyTimes, milliSecondsInterval);
}, milliSecondsInterval);
}
function delay(func, milliSeconds){
setTimeout(func, milliSeconds);
}
Promise based solution(more preferred)
repeat(processingRequest, 5, 5000);
function processingRequest(){
console.log('Making request at', new Date().getTime());
}
function repeat(func, howManyTimes, milliSeconds){
delay(milliSeconds)
.then(() => {
func();
howManyTimes--;
if(howManyTimes > 0)
repeat(func, howManyTimes, milliSeconds);
});
}
function delay(milliSeconds){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, milliSeconds);
});
}
using a library like rxjs(providing a repeat
and delay
) will make things even more simple
https://rxjs-dev.firebaseapp.com/api/operators/repeat
https://rxjs-dev.firebaseapp.com/api/operators/delay
even though not every application need rxjs, but we have to say it give the programmer a great power over clean sync or async operations
[References]
For further knowledge about Browser API & Event queue
Cool talk from Philip Roberts
https://youtu.be/8aGhZQkoFbQ?t=1165
from THE BEST great js
resource I've found
https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/async%20%26%20performance/ch1.md