Clear a Javascript Interval - javascript

I am running a HTTP Request to a file and depending on the response whether it be "200" or another response a success or error function is ran. This request takes place every second.
The problem I am facing is when I get lots of error responses they all run together and the last one doesn't stop e.g. End the interval to start a new one.
The red light begins to flash way too fast. Can anyone help me out. My code is below and I have been playing with it for a few hours now but can't seem to get to the bottom of it.
var requestResponses = {
greenLight: $('.cp_trafficLight_Light--greenDimmed'),
redLight: $('.cp_trafficLight_Light--redDimmed'),
greenBright: 'cp_trafficLight_Light--greenBright',
redBright: 'cp_trafficLight_Light--redBright',
init: function (url) {
setInterval(function () {
requestResponses.getResponse(url);
}, 1000);
},
successResponse: function () {
var redBright = requestResponses.redBright,
greenBright = requestResponses.greenBright;
requestResponses.errorCode = false;
requestResponses.redLight.removeClass(redBright);
requestResponses.greenLight.addClass(greenBright);
},
errorResponse: function () {
requestResponses.runOnInterval();
},
runOnInterval: function () {
// clearInterval(runInterval);
var redBright = requestResponses.redBright,
greenBright = requestResponses.greenBright,
redLight = requestResponses.redLight;
requestResponses.greenLight.removeClass(greenBright);
var runInterval = setInterval(function () {
if (requestResponses.errorCode === true) {
redLight.toggleClass(redBright);
}
}, 400);
},
getResponse: function (serverURL) {
$.ajax(serverURL, {
success: function () {
requestResponses.errorCode = false;
requestResponses.successResponse();
},
error: function () {
requestResponses.errorCode = true;
requestResponses.errorResponse();
},
});
},
errorCode: false
}
requestResponses.init('/status');
Appreciate the help.

Javascript is an event driven language. Do not loop inifinitely to check things periodically. There are places to do so but most of the time either calling a delay function (setTimeout) repeatedly when needed or using a callback would be better method.
Using setInterval with request, think what happens if requests start taking longer than your interval.
In your case, you have two loops created with setInterval. First one is the request which will run every 1 sec. Instead of using setInterval, you can modify your code to run setTimeout only after a request finishes and do other tasks just before re-running the next request :
function runRequest(...) {
$.ajax(serverURL, {
...
complete: function () {
setTimeout(runRequest, 1000);
}
...
});
}
function lightsOnOff() {
var redBright = requestResponses.redBright,
greenBright = requestResponses.greenBright,
redLight = requestResponses.redLight;
requestResponses.greenLight.removeClass(greenBright);
if (requestResponses.errorCode === true) {
redLight.toggleClass(redBright);
}
}
setInterval(lightsOnOff, 400);

The setInterval() method repeats itself over and over, not just one time. Your error response handler is then invoking the routine that creates another setInterval(), and so on. Until you have so many processes running that you get the flashing red light issue.
The solution is to only invoke the logic where the setInterval() call is made once. Or, even better, use setTimeout() to call the routine. It is run one-time and likely better for your use.

Related

Wait for request to finish with setInterval()

Consider the code below. This code sets an interval of 5 seconds before making another request to load the new values into part of a document.
The problem is that when a request takes a long time to resolve (>5 seconds) the requests will pile up. How can we make sure the new request will only be made when the request has finished?
In my internet search trying to answer this question, I have not come across this specific situation including setInterval. I came across a couple of suggestions using async or promises, but I have yet to discover how those could be implemented in this situation. Please forgive my inexperience in the topic.
window.onload = () => {
setInterval(refresh, 5000);
}
function refresh() {
let myVariable = document.getElementById("myId").value;
// reload part of the page for the new values
$("#partial-id").load("partial.html", {
myparameter: myVariable ,
});
}
Call the function again in the .load() callback function.
function refresh() {
let myVariable = $("#myId").val();
$("#partial-id").load("partial.html", {
myparameter: myvariable
}, function() {
setTimeout(refresh, 5000);
});
}
This will repeat the function 5 seconds after the previous one completed.
If the task performed gets wrapped into a promise, one can await it in an infinite loop:
function refresh() {
let myVariable = document.getElementById("myId").value;
return new Promise(res => {
// reload part of the page for the new values
$("#partial-id").load("partial.html", {
myparameter: myVariable ,
}, res);
});
}
(async function () {
while(true) {
await refresh();
await new Promise(res => setTimeout(res, 5000));
}
})();

How to call a function asynchronously in Javascript so that we can handle its callback and stop its execution when the time is out?

I have a function that solves a puzzle in a browser. It might take a very long time to finish and I want to stop its execution if the runtime exceeds 30 seconds. Something like this:
function solve(puzzle) {
// A loop to solve a puzzle that might take minutes to run
while (notSolve){
keepFindingSolution(); // This is not a loop
}
return solution;
}
let solution = solve(veryHardPuzzle);
if (solution && solution.solved) {
// Do something
}
console.log("Other executions");
So, I don't want to block the UI thread when solving the function so that users can still interact with the website. I also want to get the solution from the solve(veryHardPuzzle) once it's done, or break the execution of the function if the time is out.
I tried some different approaches below, but none of them work for me:
Wrap the solve() function in setTimeout()
setTimeout(function () {
let solution = solve(veryHardPuzzle);
if (solution && solution.solved) {
// Do something
}
}, 30000);
console.log("Other executions");
This approach (from https://stackoverflow.com/a/26616321/6308776) doesn't block the UI thread, and the other executions are executed happily. However, it just basically waits 30 seconds before executing the inner solve(veryHardPuzzle) function (please correct me if I'm wrong). If the solve(veryHardPuzzle) function runs longer than 30 seconds then it would block the thread.
clearTimeout() once the solve() is done
let timerId = setTimeout(function () {
let solution = solve(veryHardPuzzle);
clearTimeout(timerId);
if (solution && solution.solved) {
// Do something
}
}, 30000);
console.log("Other executions");
I thought that this would stop the timeout() after the solution is found, but it technically waits 30 seconds before the solver(veryHardPuzzle) is executed.
After doing some research, I realized setTimeout() might not the thing I want. Do you have any ideas or techniques on how to solve this?
The easiest way to handle asynchronous (like) behavior is with a Promise.
In this case you could do something like this:
function doLongThing() {
let success = false;
return new Promise(function(resolve, reject) {
//set timeout so if success is false after 30 seconds, reject promise.
setTimeout(function () {
if(!success) reject();
}, 30000)
//another set timeout to prevent blocking UX thread
setTimeout(function () {
//do long running thing
let solution = solve(veryHardPuzzle);
//thing finished
success = true;
//pass result into resolve method so consumer can use it
resolve(solution);
});
})
}
then you could do this:
doLongThing().then(function(solution) {
//do something with solution
}).catch(function() {
//timed out
});
console.log("Other executions");
A few comments have hinted at this, but the answer is not in how you call solve, but rather in how solve iterates over each “try” (I’m assuming this is how your solver works). If after each try your solver will break out of the event loop (the essence of async JS), then the main thread will have opportunities to do the other work it needs to do like handle mouse clicks or paint the UI. There are a few ways to do this, but maybe Promises is the easiest to visualize and has the best browser support (though some polyfills may be necessary for some IE versions).
var timeIsUp = false
function trySolution (puzzle, solution) {
return new Promise(function (resolve, reject) {
if (!solution) reject('no solution found')
if (timeIsUp) reject('time up!')
if (puzzle + solution !== 'wrong') { // idk lol
resolve({solution: solution, success: true})
} else {
resolve({solution: solution, success: false})
}
}
}
// solve is now recursive with each iteration async
function solve (puzzle, solutions) {
trySolution(puzzle, solutions[0])
.then(function (result) {
if (result.success) {
solve(puzzle, solutions.slice(1))
}
})
.catch(function (err) {
console.error(err)
})
}
// do the deed
solve(puzzle, solutions) // puzzle is undefined error lol
setTimeout(function () {
timeIsUp = true
}, 30000)

JSON and Python

I am developing a web interface for Arduino, using Python. For automatic updates and display, I use JSON. I have a very interesting problem.
The following code sends the command to a python function, if a command exists. Then, whether a command was sent to the function or not, the function checks for updates from the Arduino by calling another function.
Here is what I can't find any explanation to: in the first and only condition of the update() function, if I remove the line that says alert('hey'); the python function is not called anymore. But if I do write alert('hey'); after the JSON request, it works fine, the function is called and the arduino gets the message.
Anyone has an idea why?
function update(command=0) {
// if a command is passed, send it
if (command!=0) {
$.getJSON('/action?command='+command);
alert('hey'); // if I remove this, the action function is not called. Why?
}
// read from the read function, no matter what
$.getJSON('/read', {}, function(data) {
if (data.state != 'failure' && data.content != '') {
$('.notice').text(data.content);
$('.notice').hide().fadeIn('slow');
setTimeout(function () { $('.notice').fadeOut(1000); }, 1500);
}
setTimeout(update, 5000); // next update in 5 secs
});
}
update(); // for the first call on page load
Are you checking for the results of the first command with the second? If so, I suspect the alert('hey') is pausing execution long enough for the first to finish. Can you try making your read a callback function of the first getJSON?
function update(command=0) {
if (command!=0) {
$.getJSON('/action?command='+command, function() {
read();
});
} else {
read();
}
}
function read() {
$.getJSON('/read', {}, function(data) {
if (data.state != 'failure' && data.content != '') {
$('.notice').text(data.content);
$('.notice').hide().fadeIn('slow');
setTimeout(function () { $('.notice').fadeOut(1000); }, 1500);
}
setTimeout(update, 5000); // next update in 5 secs
});
}
update(); // for the first call on page load
Here's a fiddle

JQUERY AJAX ---- Pausing for usability reasons but only when nessesary?

I have a LoadingStatus Function that has two options SHOW or HIDE.
The Show triggers to display when the JQUERY POST is made, the HIDE happens after the RESPONSE comes back.
The issue I'm having is that sometimes this happens so fast that it makes for a bad experience. What I thought about doing was putting in a JavaScript PAUSE, but if the POST takes a while to respond it will take even longer because of the PAUSE.
How can I have my SHOW HIDE function work together, to make sure at minimum the SHOW was displayed to the user for at least 1/2 second?
function saveBanner (action) {
if (action == 'show') {
// Display the AJAX Status MSG
$("#ajaxstatus").css("display","block");
$("#msg").text('Saving...');
}
else if (action == 'hide') {
$("#ajaxstatus").css("display","none");
$("#msg").text('');
}
};
Thanks
In your ajax success callback, you can put the hide command in a setTimeout() for 1500 miliseconds:
success: function(results) {
setTimeout(function(){
saveBanner("hide");
}, 1500);
}
Of course that would merely add 1.5 seconds onto however long the process itself took. Another solution would be to record the time the process started, with the Date object. Then, when the callback takes place, record that time and find the difference. If it's less than a second and a half, set the timeout for the difference.
/* untested */
var start = new Date();
success: function(results) {
var stop = new Date();
var difference = stop.getTime() - start.getTime();
difference = (difference > 1500) ? difference : 1500 ;
setTimeout(function(){
saveBanner("hide");
}, difference);
}
You can perform this math either inside your callback, or within the saveBanner() function itself, within the show portion you would set the starting time, within the hide() portion you would check the difference and set the setTimeout().
You can use setTimeout/clearTimeout to only show the status when the response takes longer than a set amount of time to load.
Edit:
Some untested code:
var t_id = 0;
function on_request_start()
{
t_id = setTimeout(show_message, 1000);
}
function on_request_completed()
{
clearTimeout(t_id);
hide_message();
}
The JQuery handlers should look something like the above. The message will not be shown if you receive a reply in less than a second.
var shownTime;
function saveBanner (action) {
if (action == 'show') {
// Display the AJAX Status MSG
$("#ajaxstatus").css("display","block");
$("#msg").text('Saving...');
shownTime = new Date().getTime();
}
else if (action == 'hide') {
var hideIt = function() {
$("#ajaxstatus").css("display","none");
$("#msg").text('');
};
var timeRemaining = new Date().getTime() - shownTime - 1500;
if (timeRemaining > 0) {
setTimeout(hideIt, timeRemaining);
else {
hideIt();
}
}
};
As of jQuery 1.5, you are able to extend the $.ajax functionality by using prefilters. I wanted a similar experience where a message was shown a minimum amount of time when an ajax call is made.
By using prefilters, I can now add a property to the ajax call named "delayedSuccess" and pass it a time in milliseconds. The time that is passed in is the minimum amount of time the ajax call will wait to call the success function. For instance, if you passed in 3000 (3 seconds) and the actual ajax call took 1.3 seconds, the success function would be delayed 1.7 seconds. If the original ajax call lasted more than 3 seconds, the success function would be called immediately.
Here is how I achieved that with an ajax prefilter.
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
if (originalOptions.delaySuccess && $.isFunction(originalOptions.success)) {
var start, stop;
options.beforeSend = function () {
start = new Date().getTime();
if ($.isFunction(originalOptions.beforeSend))
originalOptions.beforeSend();
};
options.success = function (response) {
var that = this, args = arguments;
stop = new Date().getTime();
function applySuccess() {
originalOptions.success.apply(that, args);
}
var difference = originalOptions.delaySuccess - (stop - start);
if (difference > 0)
setTimeout(applySuccess, difference);
else
applySuccess();
};
}
});
I first check to see if the delaySuccess and success options are set. If they are, I then override the beforeSend callback in order set the start variable to the current time. I then override the success function to grab the time after the ajax call has finish and subtract the difference from the original delaySuccess time. Finally, a timeout is set to the computed time which then calls the original success function.
I found this to be a nice way to achieve this effect and it can easily be used multiple times throughout a site.

jQuery AJAX polling for JSON response, handling based on AJAX result or JSON content

I'm a novice-to-intermediate JavaScript/jQuery programmer, so concrete/executable examples would be very much appreciated.
My project requires using AJAX to poll a URL that returns JSON containing either content to be added to the DOM, or a message { "status" : "pending" } that indicates that the backend is still working on generating a JSON response with the content. The idea is that the first request to the URL triggers the backend to start building a JSON response (which is then cached), and subsequent calls check to see if this JSON is ready (in which case it's provided).
In my script, I need to poll this URL at 15-second intervals up to 1:30 mins., and do the following:
If the AJAX request results in an error, terminate the script.
If the AJAX request results in success, and the JSON content contains { "status" : "pending" }, continue polling.
If the AJAX request results in success, and the JSON content contains usable content (i.e. any valid response other than { "status" : "pending" }), then display that content, stop polling and terminate the script.
I've tried a few approaches with limited success, but I get the sense that they're all messier than they need to be. Here's a skeletal function I've used with success to make a single AJAX request at a time, which does its job if I get usable content from the JSON response:
// make the AJAX request
function ajax_request() {
$.ajax({
url: JSON_URL, // JSON_URL is a global variable
dataType: 'json',
error: function(xhr_data) {
// terminate the script
},
success: function(xhr_data) {
if (xhr_data.status == 'pending') {
// continue polling
} else {
success(xhr_data);
}
},
contentType: 'application/json'
});
}
However, this function currently does nothing unless it receives a valid JSON response containing usable content.
I'm not sure what to do on the lines that are just comments. I suspect that another function should handle the polling, and call ajax_request() as needed, but I don't know the most elegant way for ajax_request() to communicate its results back to the polling function so that it can respond appropriately.
Any help is very much appreciated! Please let me know if I can provide any more information. Thanks!
You could use a simple timeout to recursively call ajax_request.
success: function(xhr_data) {
console.log(xhr_data);
if (xhr_data.status == 'pending') {
setTimeout(function() { ajax_request(); }, 15000); // wait 15 seconds than call ajax request again
} else {
success(xhr_data);
}
}
Stick a counter check around that line and you've got a max number of polls.
if (xhr_data.status == 'pending') {
if (cnt < 6) {
cnt++;
setTimeout(function() { ajax_request(); }, 15000); // wait 15 seconds than call ajax request again
}
}
You don't need to do anything in your error function unless you want to put an alert up or something. the simple fact that it error will prevent the success function from being called and possibly triggering another poll.
thank you very much for the function. It is a little bit buggy, but here is the fix. roosteronacid's answer doesn't stop after reaching the 100%, because there is wrong usage of the clearInterval function.
Here is a working function:
$(function ()
{
var statusElement = $("#status");
// this function will run each 1000 ms until stopped with clearInterval()
var i = setInterval(function ()
{
$.ajax(
{
success: function (json)
{
// progress from 1-100
statusElement.text(json.progress + "%");
// when the worker process is done (reached 100%), stop execution
if (json.progress == 100) clearInterval(i);
},
error: function ()
{
// on error, stop execution
clearInterval(i);
}
});
}, 1000);
});
The clearInterval() function is becomming the interval id as parameter and then everything is fine ;-)
Cheers
Nik
Off the top of my head:
$(function ()
{
// reference cache to speed up the process of querying for the status element
var statusElement = $("#status");
// this function will run each 1000 ms until stopped with clearInterval()
var i = setInterval(function ()
{
$.ajax(
{
success: function (json)
{
// progress from 1-100
statusElement.text(json.progress + "%");
// when the worker process is done (reached 100%), stop execution
if (json.progress == 100) i.clearInterval();
},
error: function ()
{
// on error, stop execution
i.clearInterval();
}
});
}, 1000);
});
You can use javascript setInterval function to load the contents each and every 5 sec.
var auto= $('#content'), refreshed_content;
refreshed_content = setInterval(function(){
auto.fadeOut('slow').load("result.php).fadeIn("slow");},
3000);
For your reference-
Auto refresh div content every 3 sec

Categories

Resources