I need to send an ajax request with an interval of 5s
const asyncF = async () => { await /* some ajax stuff */ }
asyncF(); // fire off an ajax request first
setInterval(() => { // start an interval
asyncF();
}, 5 * 1000);
Normally the asyncF
should succeed within 5s, so 5s between sucessive starts are normally ok and simple, but I want to make sure when next asyncF fires, the previous one has succeeded. If the previous one didn't succeed, then start a new interval whenever previous one succeeds
- if
asyncF
takes less than 5s to succeed, all is good! - if
asyncF
takes more than 5s to succeed, I need to clear the interval and start a new interval wheneverasyncF
succeeds - if
asyncF
fails within 5s, I also need to immediately call it again and set a new interval
I came up with this naive idea which kind of solves the problem
let flag = true; // global variable flag
const asyncF = async () => {
await /* some ajax stuff */
flag = true;
}
try {
asyncF();
setTimer();
} catch {
asyncF();
setTimer();
}
function setTimer() {
let timer = setInterval(() => {
if (flag) {
asyncF();
} else {
clearInterval(timer);
timer = setTimer();
}
}, 5 * 1000);
return timer;
}
However with this method, if asyncF
takes more than 5s to succeed, the timer start counting before asyncF
succeeds
Is there any mature and graceful solution to solve the problem?
CodePudding user response:
It is easier to do this not with a setInterval
and have to work out when to cancel/restart it, but with a setTimeout
.
The idea is that you set a timer for 5 seconds, and if the previous function has finished you recall the function. If the timeout has been reached while the function is executing you execute it immediately, and same goes for if an error occurs.
async function limitedFunction(){
let isRunning = true;
let timeoutReached = false;
setTimeout( () => {
timeoutReached = true;
if(!isRunning)
limitedFunction();
},5000);
try{
await asyncF();
isRunning = false;
if(timeoutReached)
limitedFunction();
}
catch {
limitedFunction();
}
}
In the example below I have mocked out your asyncF
function whereby it randomly suceeds or fails (80% chance of success) and has a random delay which sometimes goes over 5 seconds. However this is no different from your ajax-based async function. It would work exactly the same way!
You should see that
- When the function succeeds in <5s it waits 5s since the original start to fire again
- When the function succeeds in >5s it starts again immediately
- When the function fails it starts again immediately.
Hopefully this matches your requirements
async function asyncF(){
const delay = (ms) => new Promise(resolve => setTimeout(resolve,ms))
const rndFunc = Math.random();
const rndTime = Math.floor((Math.random() * 7) 1);
if(rndFunc < 0.8){
console.log(`asyncF will succeed in ${rndTime}s`)
await delay(rndTime*1000)
}
else{
console.log(`asyncF will fail in ${rndTime}s`);
await delay(rndTime*1000)
throw "I failed"
}
}
async function limitedFunction(){
let isRunning = true;
let timeoutReached = false;
setTimeout( () => {
timeoutReached = true;
if(!isRunning)
limitedFunction();
},5000);
try{
await asyncF();
isRunning = false;
if(timeoutReached)
limitedFunction();
}
catch {
limitedFunction();
}
}
limitedFunction()