Set Timeout running 4 times each minute - javascript

for some reason a function I would like to execute every minute is running 4 times every minute. I would like the behavior to only fire a single time. I am unsure of why it is firing multiple times. the code is as follows:
const checkToken = () => {
console.log('im running')
const token = localStorage.FBIdToken
if (token && token !== 'Bearer undefined') {
const decodedToken = jwtDecode(token)
if (decodedToken.exp * 1000 < Date.now()) {
localStorage.removeItem('FBIdToken')
window.location.reload()
}
}
setTimeout(checkToken, 60 * 1000)
}
checkToken()

you are using this script in react, so make sure that this function/method is not triggering with component re-rendering. if you are using stateful component then move this function to componentDidMount to stop the multiple calls to this method. and if you are using stateless component then use hooks to avoid this issue
you can also use the clearInterval to avoid this issue
const timeInterVal = null;
const checkTokenFunc = () => {
if (token && token !== 'Bearer undefined') {
const decodedToken = jwtDecode(token)
if (decodedToken.exp * 1000 < Date.now()) {
localStorage.removeItem('FBIdToken')
window.location.reload()
}
}
}
const checkToken = () => {
if(timeInterval!==null){
clearTimeout(timeInterval);
}
timeInterval = setTimeout(() => {
checkTokenFunc();
checkToken();
}, 60 * 1000)
}
checkToken();

You could use setInterval() instead of setTimeout(). setInterval() you can specify a period of time and it will keep running based on the time interval you set...Pass setInterval() a function to execute and a time interval in milliseconds. The below will execute every 5 seconds.
Example:
setInterval(function(){ alert("Hello"); }, 5000);

Related

JavaScript clear timeout not working with React useEffect return function

For some reason, I need to call checkProgess function for the first 2 minutes with 10 seconds of delays.
So I did it like this
const [timers, setTimers] = useState<ReturnType<typeof setTimeout>[]>([]);
useEffect(()=>{
for (let index = 0; index < 12; index++) {
const seconds = (index+1)*10000;
let timer = setTimeout(() => {
checkProgress(id, setFieldValue, contractType, fileOCRStatus);
}, seconds);
console.log("timer",timer)
setTimers((prev) => {
prev.push(timer)
return prev
});
}
},[])
within these 12 tries, this component will unmount if the progress checks succeed. In that time I do want to clear all the remaining timeout calls. I did it like this in the useEffect return function.
return () => {
console.log("Return function called",timers)
timers.forEach((timer) => clearTimeout(timer));
};
This part is executed successfully but the cleaning thing seems not working. I CAN SEE THE API CALLS RUNNING AFTER THE COMPONENT IS UNMOUNTED.
what went wrong here?
In console.log("Return function called", timers) timer ids also print correctly.
You don't actually need to store these in a state since this useEffect is only running once (and even if it wasn't, since you're cleaning up the timers in the returned function, you don't need to keep the value across renders).
// delete the useState stuff
useEffect(() => {
const timers = [];
for (let index = 0; index < 12; index++) {
const seconds = (index+1)*10000;
const timer = setTimeout(() => {
checkProgress(id, setFieldValue, contractType, fileOCRStatus);
}, seconds);
console.log("timer",timer)
timers.push(timer);
}
return () => {
timers.forEach((timer) => clearTimeout(timer));
}
}, []);

Call an API every 2 seconds for a period of one minute using react hooks

I am trying to make an api call (API1) every 2 seconds for a period of 1 minute. During this minute I need to exit the interval if condition is met and do another API call (API2). The problem that I am facing is if the API1 get into a pending state for more than 2 seconds, the second call of API1 will start and again if in pending state for 2 seconds the third call will happen ending up with quite few calls for same api all under pending state …. How can I stop the subsequent calls until the previous call is resolved?
useEffect(() => {
if (triggerTheInterval) {
startInterval()
return () => clearInterval(id)
}
}, [triggerTheInterval])
onClick = () => {
makefirstcallforapi1();
}
//this is only to get the first call at first second - before the 2 seconds interval starts
const makefirstcallforapi1 = () => {
setTimer(new Date().getTime());
fetch(url).then(res => {
if (conditionmet) {
//do the API2 call
} else {
setTriggerTheInterval(true)
}
})
startInterval = () => {
id = setInterval(() => {
fetch(url).then(res => {
if ((new Date().getTime() - startTime > 60000 || condtionmet) {
//do something then exit the interval
}
})
}, 2000)
}

Multiple apis trigger without using settimeout

I have calling dataUpdate function every 4 second until records length to 0.
Inside the dataUpdate this.callAPI(); is trigger api call.
I set manual timeout for 4 seconds to call the function to callapi.
Instead of timeout ,how to call the api immediately after previous api completed.
dataUpdate =()=> {
var arrayList = this.arrayList;
if(arrayList.length > 0)
{
var inputData = {
...inputData,
data:{
...inputData.data,first:'',second:''
}
};
var first = arrayList[0].first;
var second = arrayList[0].second;
inputData.data.first = first;
inputData.data.second = second;
this.setState({ inputData:inputData });
this.callAPI();
arrayList.shift();
this.arrayList = arrayList;
if(arrayList.length !== 0){
setTimeout(() => {
this.dataUpdate();
}, 4000);
}
if(arrayList.length === 0){
setTimeout(() => {
this.props.callMessage(this.totalCount);
}, 1000);
}
}
}
Your problem is in having state. Make callapi function stateless and pass all needed parameters so you can call it any amount of times and do not rely on previous call or state

clearInterval in web worker not stopping timer

my question has been asked once here:
clearInterval in webworker is not working
The solution seems clear but for some reason it is not working for me yet. I have a web worker that is sending an interval back to the main thread. I want to be able to stop the interval with clearInterval, but it is not working.
I have it set up exactly the same as it suggests in the previous question, but still no luck. I have added some console.logs to verify I'm in the correct block. "Stop" logs to the console when it supposed to, but the timer doesn't stop posting to the main thread.
Can anyone spot what's going on here?
Thanks
worker.js
let mytimer;
self.onmessage = function(evt) {
if (evt.data == "start") {
console.log("start")
var i = 0;
mytimer = setInterval(function() {
i++;
postMessage(i);
}, 1000);
} else if (evt.data == "stop") {
console.log("stop")
clearInterval(mytimer);
}
};
Then I'm calling this from my React hook when timer.time is above or below a certain value (2000 in this case)
main.js
const worker = new myWorker()
useEffect(() => {
worker.addEventListener('message', function(e) {
//from interval in the worker
console.log('Message from Worker: ' + e.data);
})
if(timer.time > 2000){
worker.postMessage("start")
}else{
worker.postMessage("stop")
}
},[timer.time])
You should also clear the interval when you start a new interval. If you don't do it, your previous interval would keep running, and you'll lose the ability to clear it:
let mytimer;
self.onmessage = function(evt) {
console.log(evt.data)
if(evt.data === 'start' || evt.data === 'stop') {
clearInterval(mytimer);
}
if (evt.data == "start") {
var i = 0;
mytimer = setInterval(function() {
i++;
postMessage(i);
}, 1000);
}
};
You should create a single instance of the worker, and store it as ref:
const worker = useRef()
useEffect(() => {
worker.current = new myWorker()
return () => {
worker.current.terminate();
}
}, [])
Not related, but in addition, the useEffect adds a new event listener whenever timer.time changes, without clearing the previous one. I would split this into 2 useEffect blocks, one for sending (which can be combind with the creation of the worker), and the other for receiving.
useEffect(() => {
const eventHander = e => {
//from interval in the worker
console.log('Message from Worker: ' + e.data);
}
worker.current.addEventListener('message', eventHander)
return () => {
worker.current.removeEventListener('message', eventHander)
}
}, [])
useEffect(() => {
worker.current.postMessage(timer.time > 2000 ? 'start' : 'stop')
}, [timer.time])
I'm not sure about web workers but I am very familiar with using intervals in useEffect. Since useEffect is called everytime your dependencies change (timer.time), you need to store the interval in a useRef unless you are going to be clearing it before your dependency next changes

Update data every 60 sec - vanilla js SPA

I have this function that renders some html, and I don't know how to call setInterval function here, to call render func after every 60 sec
const Home = {
render: async () => {
const cryptos = await getAllCryptos();
const view = `
<section class="section">
<table>
${cryptos.data.map(crypto =>
`<tr>
<td class="name">${crypto.name} </td>
<td>${crypto.symbol}</td>
<td>${crypto.quote.USD.price}</td>
<td>${crypto.quote.USD.percent_change_24h}</td>
</tr>`
)}
</table>
</section>
`;
return view
}
};
export default Home;
I cant really put render function inside setInterval, so I am wondering what is the best way to do it?
Indeed, using setInterval would be chaotic given that render involves asynchronous processing.
Instead, a chained series of setTimeout would probably be best:
const RENDER_INTERVAL = 60000; // 60 seconds in milliseconds
function handleRender() {
Home.render()
.then(html => {
// ...use the HTML...
})
.catch(error => {
// ...report the error...
})
.finally(scheduleRender);
}
function scheduledRender() {
setTimeout(handleRender, RENDER_INTERVAL);
}
That code assumes you want to continue even if one call to Home.render fails.
If you want to use 60 seconds from the beginning of the last call to render rather than the end (the above is 60 seconds from the end), you'd do a bit more logic:
const RENDER_INTERVAL = 60000; // 60 seconds in milliseconds
let lastRenderStart = 0;
function handleRender() {
lastRenderStart = Date.now();
Home.render()
.then(html => {
// ...use the HTML...
})
.catch(error => {
// ...report the error...
})
.finally(scheduleRender);
}
function scheduledRender() {
setTimeout(handleRender, Math.max(0, RENDER_INTERVAL - (Date.now() - lastRenderStart));
}
handleRender();

Categories

Resources