Prevent JavaScript Timer Re-entry - javascript

My ASP.NET MVC page uses JavaScript/jQuery to poll my database every second.
This is working but I want to make sure that, if there is a delay, my timer handler won't get called again before it has returned.
In there any trick to this other than storing the timer ID in a global variable, clearing the timer in my handler, and restarting it when my handler is done.
NOTE: I realize every second seems frequent but this code is polling my server after submitting a credit card payment. Normally, it will only run for a second or so, and I don't want the user to wait any longer than necessary.

Polling every second? That's quite heavy!
That aside, you won't have this issue when setTimeout is used instead of setInterval. The latter ensures that a piece of code is run x times given a interval, while the former ensures that there's a delay of at least x milliseconds.
function some_poller() {
$.ajax({
url: '/some_page',
success: function() {
setTimeout(some_poller, 1000);
},
error: function() { // Also retry when the request fails
setTimeout(some_poller, 1000);
}
});
}
// Init somewhere
some_poller();

Not really, although I wouldn't recommend using a global variable. Stick it inside some function.
But are you really sure you need to poll every second? That's an extremely chatty interface.

In my personal experience a "global", (inside of the root function), variable works very well in this instance so that you can control when to clear and restart. If the response is really as quick as you say, this shouldn't cause too much overhead, (clearing/resetting), and will allow to account for these type of situations.

Related

How to put a sleep after clicking a button

I would like to put a delay after a button is pressed in order for the button to load the data from the cache before executing the next line of code. Would putting a sleep be the best way to do this?
Something like this or is there an alternative approach to best solve this problem?
setInterval(document.getElementById("generateButton"), 1000);
Don't use setInterval to do this. It doesn't have the functionality you seem to desire (it repeats). Instead, use jQuery and do something like this:
$("#generateButton").click(function(event){
setTimeout(function(){
//Do what the button normally does
}, 1000);
});
Or (without JQuery):
var generateButton = document.getElementById("generateButton");
generateButton.addEventListener("click", function(){
setTimeout(function(){
//Do what the button normally does
}, 1000);
});
Using setTimeout over setInterval is preferred in your case because setTimeout runs only once while setInterval runs multiple times.
I assume you have, in your html, <button id='generateButton' onclick='someFunction()'>Button Text</button>. Remove the onclick='someFunction() and put your someFunction() where I said (in the examples) "Do what the button normally does."
You can also add in the code that loads the cache a method that calls another method once the cache has been loaded (when the someFunction() from the button is called, it loads the cache, and at the end of the function (set this up using callbacks), once the cache has been loaded, it calls another method onCacheLoaded() that can be run once the cache has been loaded.
You should use callbacks, so the moment you loaded data from cache you can call it and continue executing the rest of the script.
You cannot use interval since you cannot be sure how much time is needed for the data to load. Though keep in mind the asynchronous nature of javascript and don't block the part of the script that does not depend on the data that's being loaded.
Try setTimeout:
myButton.addEventListener('click', function() {
setTimeout(delayed, 1e3); // Delay code
}, false);
function delayed() {
// Do whatever
}
Note setInterval runs a function periodically, setTimeout only once.
Also note that the delayed code must be a function (or a string which will be evaluated, but better avoid that). However, document.getElementById("generateButton") returns an html element (or null).

jquery ajax compatibility in IE

$(document).ready(function () {
var searchValue = "";
setInterval(checkTextboxChanged, 0.5);
function checkTextboxChanged() {
var currentValue = $('#dept').val();
if (currentValue != searchValue) {
searchValue = currentValue;
TextboxChanged();
}
}
function TextboxChanged() {
$.ajax({
url: "<?php echo base_url();?>check_price.html",
data: "dept="+$("#dept").val()+"&arrive="+$("#arrive").val()+"&parking="+$("#parking").val(),
success: function(result){
$("#check_price").html(result);
}
});
}
});
This is working fine in Chrome,firefox but not in IE.. is it any problem in setInterval method? is it supports IE?
setInterval with a small timeout is a really really bad idea, whichever browser you're using.
The thing with setInterval is that the event is triggered on the specified interval regardless of whether the page is ready for it.
With a short interval time, this can very easily lead to a pile-up of events that are fired faster than the site can deal with them.
Your usage here, with ajax involved is a classic example of this: If the ajax event takes longer than half a second to complete (which is easily possible), then you'll end up with multiple events being called virtually simulataneously. This will lead to your ajax service being swamped with simultaneous calls, which will make its response time slow down, and in turn make the problem in the browser even worse.
With this kind of thing, it is almost always better to use a self re-firing setTimeout call, which will ensure that the event is never triggered until the previous one has completed.
However, either way, your interval of 0.5ms is a crazy short time span for any kind of interval handling. You will very likely have performance issues with a timeout that short, whatever it is you're doing.
I suspect that you actually intended it to be half a second rather than half a millisecond. If that's the case, you should change it to 500 rather than 0.5.

Run js function once when fired more than once

I have a Div that uses jQuery to load a file/contents with a javascript function..
function DoWork() {
// Do Stuff
}
Let's say the user can reload the Div and pull the same file/contents with the same js function DoWork(). The problem is, when the file is reloaded, the previous loaded function DoWork() is still running. How can I kill the previous fired DoWork() and restart it?
Javascript is single-threaded, which means only one thing can be executing at a given moment. If DoWork is already "running" it's either a) blocking all other JS code, and you have no choice but to let it finish since you have no way to execute any interruption code until it finishes on its own, or b) DoWork is scheduled to fire off on an interval via setTimeout() or setInterval().
If it's the latter case, setTimeout() and setInterval() return an ID. Store that ID somewhere and call clearTimeout(doWork_timeout_id) or clearInterval(doWork_interval_id) according to how you started it.
You can build a simple function that use: setTimeout and then each call to DoWork will call first to: clearTimeout. I don't really like this solution because you will waste CPU on setTimeout.
So another option will be to use web worker in DoWork (It will do lots of other good things for you in case you are working with big data as it's running in another thread) - then you get an option to send 'stop' message each time you start the work of DoWork().
Are you using ajax to load the div's contents? if so, the better way is as follows:
var doWorkAjax=null;
function DoWork(){
if (doWorkAjax) doWorkAjax.abort();
doWorkAjax = $.ajax(url, data, function(result){
....
doWorkAjax=null;
});
}

jQuery/JavaScript: interrupt event?

This is a really basic JavaScript question and probably duplicate, but I don't know the answer!
I have code as follows:
function userlist_change(myval, function_type) {
// relatively slow code involving Ajax call
// based on Ajax results, change some client-side stuff
}
$("#subjectlist").change(function() {
userlist_change($("#subjectlist").val(), 'change');
}).change();
$("#subjectlist").keypress(function() {
userlist_change($("#subjectlist").val(), 'keypress');
});
I have the problem that if the .change() event is called, the userlist_change function kicks off, and it's relatively slow. If the user changes the list again (e.g. by typing), my code waits for userlist_change to complete before restarting it with the new value.
This looks quite odd in the UI, as it can take a few seconds for anything to change client-side - and sometimes the results of the first call only appear after the user has already made a second call.
Is there any way I can interrupt any existing userlist_change process when the .change() or `keypress() event is fired?
[EDIT] What would be ideal is a simple 'kill any running functions with this name' command - is this possible? Or do I really have to fiddle around with timers?!
you can store last request time in a global variable, and store a request time in each ajax request, so that when you are just showing the result of first request, if the global last request time is greater than request, request time, you should show, other wise not. For example:
var lastRequestTime;
function userlist_change(myval, function_type,requestTime) {
// relatively slow code involving Ajax call
// based on Ajax results, change some client-side stuff
if(lastRequestTime <= requestTime){
//show
}
}
$("#subjectlist").change(function() {
lastRequestTime = new Date();
userlist_change($("#subjectlist").val(), 'change',lastRequestTime );
}).change();
$("#subjectlist").keypress(function() {
lastRequestTime = new Date();
userlist_change($("#subjectlist").val(), 'keypress',lastRequestTime );
});
You should use throttling of event. It is quite easily done with RX for JavaScript, but library is quite complicated. You can try filter value with timer.
Here is useful plugin for throttling: http://benalman.com/projects/jquery-throttle-debounce-plugin/

Is it OK to call clearInterval inside a setInterval handler?

I have a piece of Javascript that checks for a condition (via an AJAX call) every n seconds. If that condition is true, it stops checking. I have implemented it in the following way:
var stopTimer;
var timerId = setInterval(function() {
/* Make Ajax Calls and set stopTimer */
if (stopTimer) {
clearInterval(timerId);
}
}, 10000);
However, I find erratic behaviour: Works sometimes, but at other times, it keeps checking forever. I have checked that (as much as is possible) there is no error in any part of the code.
I am therefore suspecting that calling clearInterval inside a setInterval handler might be the culprit. Is that right? Is it OK to call clearInterval inside a setInterval handler?
Thank you for your attention
It's safe. The issue is probably to do with stopTimer not being set as you expect.
I don't think there will be any issue with your code unless the AJAX function is erroneous. You have to take care of the success and error callbacks of the AJAX function so that there won't be any issue with the loop not being stopped.
Also I think you are constantly polling the server for a response and then doing the appropriate action. You can use Reverse AJAX to do this kind of process.
Make sure you're not inadvertently re-using the same timer name elsewhere in your code which would result in you always stopping the second timer to be defined.
Either give the timer a unique name, or scope it to a function
var timerForAjax = setInterval(function() {
/* Make Ajax Calls and set stopTimer */
if (stopTimer)
{
clearInterval(timerForAjax);
}
}, 10000);
I was careless enough to call my timer interval and didn't realize I was creating two timers in the same scope both called interval. Blamed iOS8 for about an hour until I realized that that was nothing to do with it.

Categories