How to clear interval after status change in an API response? - javascript

Let's say I have a checkStatus() method which is triggered after a response to an endpoint is successful. Inside this there is a setInterval like so:
checkStatus() {
setInterval(() => {
client
.query({
query,
variables,
})
.then(res => {
if (res.status) {
console.log("FINISHED!");
}
});
}, 3000);
}
Basically I am querying an endpoint every 3 seconds. Once the res.status becomes true, I want to clear the interval. The component is still there and hasn't unmounted yet.
How do I achieve this?

Just clear interval in your check condition.
Example:
checkStatus() {
const interval = setInterval(() => {
client
.query({
query,
variables,
})
.then(res => {
if (res.status) {
console.log("FINISHED!");
clearInterval(interval)
}
});
}, 3000);
}

Basically you need to assign a value to the setInterval function and clear it into your callback:
checkStatus() {
const intervale = setInterval(() => {
client
.query({
query,
variables,
})
.then(res => {
if (res.status) {
console.log("FINISHED!");
clearInterval(intervale)
}
});
}, 3000);
}

You need to first store the reference returned by setInterval and pass it to clearInterval to clear it. For example, storing the reference in a variable ref -
checkStatus() {
const ref = setInterval(() => {
client
.query({
query,
variables,
})
.then(res => {
if (res.status) {
clearInterval(ref);
console.log("FINISHED!");
}
});
}, 3000);
}

Assign a variable to the interval and clear the interval based on the condition
this.interval = setInterval(() => {
client
.query({
query,
variables,
})
.then(res => {
if (res.status) {
console.log("FINISHED!");
clearInterval(this.interval)
}
});
}, 3000);
checkStatus() {
this.interval()
}

Related

React.js and Firebase auth: setTimeout Callback function not executed?

I have a function handleSubmit that handles registering in Firebase in a react component. Inside, I want to handle errors with my setErrorTimeout function, which has a setTimeout that resets the error automatically after 3 seconds in this case..
The problem is, my Timeout is not executed, e.g the callback function inside the timeout is not being executed after 3 seconds, but everything else is.. why?
const handleSubmit = async e => {
e.preventDefault()
console.log(formDetails)
if (formDetails.password !== formDetails.passwordrepeat) {
setErrorTimeout(setRegisterError, {
message: 'Passwords do not match!',
})
return
}
console.log('Try')
console.log(formDetails.email, formDetails.password)
try {
auth.createUserWithEmailAndPassword(
formDetails.email,
formDetails.password
)
.then(userCredentials => {
if (userCredentials) {
const user = userCredentials.user
let success = user.sendEmailVerification()
console.log('success register:', success)
setRegisterSuccess(
'You registered successfully! please check your email!'
)
setFormDetails({})
}
})
.catch(error => {
console.log('ERROR!')
setErrorTimeout(error)
})
} catch (e) {
setErrorTimeout(e)
}
}
const setErrorTimeout = error => {
console.log('inside timeout!')
setRegisterError(error)
const timer = setTimeout(() => {
console.log('inside cb!')
setRegisterError(null)
}, 3000)
clearTimeout(timer)
console.log('after timeout!')
}
You're clearing the timeout right after you create it here:
const timer = setTimeout(() => {
console.log('inside cb!')
setRegisterError(null)
}, 3000)
clearTimeout(timer)
You probably want that clearTimeout call to be inside the callback, although it's not even strictly needed since the timeout already fired.

How to fix setTimeout behavior over HTTP requests?

On my client app, I'm using Socket IO to check for unread events. I make a request to my backend, which sets a timeout of 5 seconds, then proceeds to check for unread events and sends any back.
// client
socket.on("response", ({ mostRecentMessages }) => {
// do some stuff first
socket.emit("listenForNew", { userId, currentMessagesFromEveryone });
})
// backend
socket.on("listenForNew", ({ userId, currentMessagesFromEveryone }) => {
if (currentMessagesFromEveryone && userId) {
const { MostRecentMessages } = require("./constants/models");
const filteredIds = [];
currentMessagesFromEveryone.forEach(message => {
filteredIds.push(message.conversation._id);
});
console.log("Entered!");
setTimeout(async () => {
const mostRecentMessages = await MostRecentMessages.find({
to: userId,
date: { $gt: connectedUsersAllMessages[userId].timeIn },
conversation: { $nin: filteredIds }
}).populate("to from conversation");
allMessagesSocket.sockets.connected[
connectedUsersAllMessages[userId].socketId
].emit("response", {
mostRecentMessages
});
}, 5000);
}
});
At first, it works fine. It prints Entered! one time for about 4, 5 requests. Then on the 6th, it starts to print Entered! twice.
Why is this happening and what am I doing wrong?
I'm in favor of the below approach:
Wait for X seconds (5 in our use case)
Call an async operation (execution time in unknown)
Wait until async execution complete
Wait for another X seconds before executing the next call
Implementation may be something like that:
const interval = 5000;
function next() {
setTimeout(async () => myAsyncOperation(), interval);
}
function myAsyncOperation() {
const mostRecentMessages = await MostRecentMessages.find({
to: userId,
date: { $gt: connectedUsersAllMessages[userId].timeIn },
conversation: { $nin: filteredIds }
}).populate("to from conversation");
allMessagesSocket.sockets.connected[
connectedUsersAllMessages[userId].socketId
].emit("response", () => {
mostRecentMessages();
next(); // "next" function call should be invoked only after "mostRecentMessages" execution is completed (or a race condition may be applied)
});
}
next();
I haven't compiled this code but I hope that the concept is clear

Calling a function in setInterval gives error in react native

I am working on a React Native app where I'm trying to call a function in setInterval to re-render component in every three seconds. But when I put the function in setInterval it returns the error this.refreshData() is not a function. Here's the code for this I'm having:
refreshData = async()=> {
await fetch('https://myapi', {
method: 'GET',
})
.then((response) => response.json())
.then((response) => {
this.setState({ tableData1: response.First })
this.setState({ tableData2: response.Special })
this.setState({ tableData3: response.Consolidation })
})
}
componentWillMount() {
const { navigation } = this.props;
this.focusListener = navigation.addListener("didFocus", () => {
var today = new Date()
var time = today.getHours()
console.log(today.getMinutes())
var weekDay = today.getDay()
if ((time >= 22) && (time <= 23 )){
if(today.getMinutes()<=30){
setInterval(function() {
this.refreshData()
}, 3000);
}
});
}
How this error can be resolved?
Use arrow function.
Try this example:
function refreshData(){
console.log("called");
}
setInterval(() => {
this.refreshData();
}, 3000);
Either bind the setTimeout/setInterval function or use Arrow function i.e
setTimeout(function() { //or setInterval(whatever you need to use)
this.refreshData()
}, 3000);
}
}).bind(this);
or
setTimeout(() => { //or setInterval(whatever you need to use)
this.refreshData();
}, 3000);

JS setInterval is being called multiple times

I'm having following code
if (input.isValidLink()) {
store()
.then(db => db.update(message.from, text, json))
.then(value => value.selectAllFromDB())
.then(users => makeRequest(users));
}
Amd makeRequest function
makeRequest(user) {
setInterval(() => {
users.forEach(user => {
httpRequest(user.json);
});
}, 10000);
}
What I'm trying to do, is selectAllFromDB function returns array of users from db, and it passed as argument to makeRequest function, which is looping thru each user, send request to receive json data and do it each 10 seconds, so it will not miss any changes. Each time when any user send the link, it should also start watching for this link. Problem is that on each received link it calls makeRequest function which creates another interval and if two links were received, I'm having two intervals. First looping thru this array
[{
id: 1234,
json: 'https://helloworld.com.json',
}]
And second thru this
[{
id: 1234,
json: 'https://helloworld.com.json',
}, {
id: 5678,
json: 'https://anotherlink.com.json',
}]
Is there any way this can be fixed so only one interval is going to be created?
You need to do something like this to make sure you only create one interval and are always using the latest users list:
let latestUsers;
let intervalId;
const makeRequest = (users) => {
latestUsers = users;
if (!intervalId) {
intervalId = setInterval(() => {
latestUsers.forEach(user => {
httpRequest(user.json);
});
}, 10000);
}
}
If you don't want variables floating around you can use a self-invoking function to keep things nicely packaged:
const makeRequest = (() => {
let latestUsers;
let intervalId;
return (users) => {
latestUsers = users;
if (!intervalId) {
intervalId = setInterval(() => {
latestUsers.forEach(user => {
httpRequest(user.json);
});
}, 10000);
}
}
})();

Angular2 Observable with interval

I have a function that needs to be called about every 500ms. The way I am looking at doing it with angular2 is using intervals and observables. I have tried this function to create the observable:
counter() {
return Observable.create(observer => {
setInterval(() => {
return this.media.getCurrentPosition();
}, 500)
})
}
With this code for the subscriber:
test() {
this.playerService.initUrl(xxxx) // This works
this.playerService.counter().subscribe(data => {
res => {
console.log(data);
}
})
}
I am very new to observables and angular2 so I might be taking the wrong approach completely. Any help is appreciated.
The Observable class has a static interval method taking milliseconds (like the setInterval method) as a parameter:
counter() {
return Observable
.interval(500)
.flatMap(() => {
return this.media.getCurrentPosition();
});
}
And in your component or wherever:
test() {
this.playerService.initUrl(xxxx) // This works
this.playerService.counter().subscribe(
data => {
console.log(data);
}
);
}

Categories