jQuery: delay interval of ajax function till previous run is completed - javascript

I've set up an AJAX page refresh with setInterval.
From time to time, the server is so slow that a new request is initiated before the previous one has completed.
How can I prevent that?

Use a timeout value that is shorter than your refresh interval. When the request times out, it will call the error handler so you'll need to differentiate between time out errors and other types of errors in the handler.
$.ajax({
type: "POST",
url: "some.php",
data: "name=John&location=Boston",
timeout: 5000, /* ms or 5s */
success: function(msg){
alert( "Data Saved: " + msg );
}
});
Docs at jquery.com. Example above from same source, but with added timeout value.

Use setTimeout instead, initiate another setTimeout only after receiving the result of the AJAX request. That way a refresh only happens after the specified period since the last refresh.

Instead of using a fixed, hard coded interval: Trigger the next refresh as the last step of handling the current one, e.g. in the "Success" (or "Complete") event callbacks.
You could add a variable that keeps track of the time the current request was sent, so that you can calculate a dynamic delay:
take current time T1
send asynchronous request
other stuff happens...
asynchronous request returns, callback executes
subtract T1 from current time
if result < your desired request interval, set delay value > 0
if result >= your desired request interval, set delay value = 0
call setTimeout with the delay value, initiating the next cycle

What I can tell you is, use a flag in your code.
Like (not what I actually recommend just a simple example)
var isWorking = false;
function doRequest(){
if(isWorking) return;
isWorking = true;
$.ajax({
...,
success: workWithResponse
});
}
function workWithResponse(){
/* doAnythingelse */
isWorking = false;
}
setInterval(doRequest,1000);
Something like that, its primitive but you will avoid race conditions.
Regards.

Related

Why my setInterval function doesn't stop

I need to write a setInterval function in javascript. Thi is the code:
var myTimer=setInterval(function(){
var time=0;
$.ajax({
url:'...'
type: "POST",
dataType:"",
success: function (response) {
if(response=="true" || time>=10000){
clearInterval(myTimer);
}
time=time+1000;
},
error: function () {
alert("FAIL");
}
});
},1000);
I don't know why It doesn't stop in clearInterval. Anyone can help me?
You've claimed that the code does "come in the 'if'", so I assume the clearInterval call is actually being made.
Given that, the most likely explanation is that the interval is being cleared (after all, select isn't broken), but before the first "true" response, you've already made more than one ajax call, and the other ones you're seeing are ones scheduled before the interval was cleared.
E.g., your code runs and:
Fires off ajax call #1, which takes more than a second to complete
Fires off ajax call #2
Ajax call #1 completes but isn't "true"
Fires off ajax call #3
Ajax call #2 completes and is "true", clearing the interval
Ajax call #3 completes
Mixing two separate asynchronous intervals (one via setInterval and one via ajax) is asking for trouble.
If the goal is to make the request once a second and stop when you get back "true", I would have the success handler schedule the next call, e.g.:
(function() {
var time = 0;
var started = 0;
start();
function start() {
started = Date.now();
$.ajax({
url: '...'
type: "POST",
dataType: "",
success: function(response) {
if (response != "true") {
// Schedule the next call to occur one second after we
// started the previous call; or almost immediately if
// the call took more than a second to complete
setTimeout(start, Math.max(0, 1000 - (Date.now() - started)));
}
time = time + 1000;
},
error: function() {
alert("FAIL");
}
});
}
})();
Let me illustrate the expected and the actual scenarios to make things clearer.
Scenario #1
The image below shows the case where all your ajax requests complete before one second. You will notice that ajax callback success (or error) functions will execute only before clearInterval (which is what you always expect).
Scenario #2
When some of your ajax requests take more than one second (which is probably what happens), then your ajax callbacks can fire before / after / before-and-after the clearInterval, which makes you feel that your setInterval doesn't stop.
Note that your time variable is useless because it's a function-scoped variable that you initialize to 0 every function call. And even if it's a global variable, it'll only clear the interval in the 11th success function callback, and nothing guarantees how long these 11 successful requests will take.
Solution
As T.J. Crowder suggested, it's better to schedule the next ajax call in the success callback of the previous one, which guarantees that your ajax requests fire sequentially (only one at a time).
Note: Because you edited your question after his answer, then you'll also need to edit the if condition like this:
success: function(response) {
if (response != "true" && time < 10000) {
setTimeout(start, Math.max(0, 1000 - (Date.now() - started)));
}
}

Prevent ajax requests from timing out (jquery)

I have about 100 ajax requests that I fire at the same time, I thought browsers only allowed a few requests simultaneously, so the rest would be added to a queue.
The problem however is that jquery/javascript seems to use the timeout value from the time the requests were created via jquery, not from the time the requests were actually executed by the browser. So I get a bunch of timeouts. Is it possible to have the timeout start counting from the time the request is actually going to the URI location, instead of the time it is added by jquery?
You may use the timeout settings for ajax request. You may find the jQuery documentation for the same at : http://api.jquery.com/jQuery.ajax/
However the timeout period starts at the point the $.ajax call is made; if several other requests are in progress and the browser has no connections available, it is possible for a request to time out before it can be sent. Therefore you should set some very large value for the timeout if you wish to follow this approach.
A better approach would be to have a local proxy which entertains all the AJAX calls and fires them in a group of 5-10 and then when all these have finished successfully then it fires the next 5-10 requests.
Here is a kind of queue system. Starts by calling the ajax function N times, and then after each success, calls ajax function again. There is also a check in the success callback to see if all the assets have been loaded...
demo fiddle
$(document).ready(function(e) {
$("form[ajax=true]").submit(function(e) {
e.preventDefault();
var form_url = $(this).attr("action");
var form_method = $(this).attr("method").toUpperCase();
$("#loadingimg").show();
var started = 1, done = 0;
function ajax(){
$.ajax({
url: form_url,
type: form_method,
data: "html=started "+(started++),
cache: false,
success: function(returnhtml){
done++;
$("#result").html(returnhtml);
$("#loadingimg").hide();
if(started <= 100){
ajax();
} else if (done == 100) {
alert("all done!");
}
}
});
}
// how many concurrent calls?
for(i=0;i<10;i++){
ajax();
}
});
});

Can't cancel set.interval

Checking for internet connection with the following code...
var checkstatus = 0
function checkConnection()
{
$.ajax({
url: "https://path/to/a/file.html",
data: { method: 'checkConnection'},
dataType: "html",
success: function(html)
{
clearInterval(checkstatus);
console.log('connection available');
return;
}
},
error: function(XMLHttpRequest, textStatus, errorThrown){
console.log('retrying');
checkstatus = setInterval(function(){checkConnection()},10000);
}
});
}
The line clearInterval(checkstatus); does not work as the script continues checking every 10 seconds, why is this?
HTTP request is made
Error response comes back
Interval 1 is created calling checkConnection every 10 seconds
HTTP request is made
Error response comes back
Interval 2 is created calling checkConnection every 10 seconds
HTTP request is made
Success response comes back
Interval 2 is cancelled
… but interval 1 is still running.
Don't start the interval inside the error response. Either do it as the means by which you start the very first run of checkConnection or use setTimeout instead.
setTimeout is probably better as it will avoid race conditions in which the request takes more than 10 seconds to get a response.
setInterval sets a callback to run every X seconds, and returns the ID of that callback. You're setting an additional callback to run every time your error callback happens, overwriting the previous interval's ID, but not cancelling it. When you finally do cancel an internval, it's only the last one you created.
Your error callback needs to test that setInterval hasn't already been called:
if (checkstatus == 0)
checkstatus = setInterval(function(){checkConnection()},10000);
I think it is easier if you would use setTimeout instead of the setInterval and you don't need to use the clear it then.

Sending jQuery ajax request on keyboard input

I'm sending an ajax request to the server on user's input to an <input> element, like this:
$('#my-input').bind("input", function(event){
// here's the ajax request
});
What bothers me is that it send unnecessarily many requests on every user's keyup, meaning that if the user types very fast, there are many unnecessary requests. So I get the idea that there should be a certain delay/timeout, which waits a certain time (50 miliseconds?) for the user to stop typing before sending the ajax request. That would be one problem solved.
But what about cases when the first ajax request haven't been completed before sending another request? (Typing 60 ms / char while ajax request taking 300 ms).
What is the best way to solve this problem (both idea- and code-based)?
You can use throttle function in underscore library. As its documentation says:
Creates and returns a new, throttled version of the passed function, that, when invoked repeatedly, will only actually call the original function at most once per every wait milliseconds. Useful for rate-limiting events that occur faster than you can keep up with.
Even if you don't want to introduce a new library, you can still get idea about how this function works from its source code. In fact, a simple version of throttle function could be:
function throttle(func, delay) {
var timeout = null;
return function() {
var that = this, args = arguments;
clearTimeout(timer);
timeout = setTimeout(function() {
func.apply(that, args);
}, delay);
};
}
This jQuery throttle-debounce plugin is also helpful. Especially, the debounce function seems more suitable to your needs than throttle function according to its author:
Debouncing can be especially useful for rate limiting execution of handlers on events that will trigger AJAX requests
You could just use the setTimeout function. Every so often, see if the text hasn't changed, and if it hasn't, then process accordingly.
setTimeout(function() {
// Do something after 1 second
}, 1000);
You can set async: false in your ajax request so it will process second ajax call only after completion of first ajax request.
I'd go with #HuiZeng's answer, but just in case you want a slightly modified version.
Steps
Listen to keydown using a setTimeout that you can clear.
When it fires, check if you have a previous request in queue, if so abort it and fire a new one
Example:
var inputTimer = 0, req;
function onInput(e){
clearTimeout(inputTImer);
inputTimer = setTimeout( function(){
// You have access to e here
// Cancel any previous requests
req && req.abort();
req = $.ajax({/*...Do your magic here :)*/})
}, 100)
}

time an ajax request

Is there any way to time how long a jquery ajax request has been going on? sometimes searches take too long and it would be nice to add a jquery abort() button if the search takes over, say, 5 seconds. Any way I can do this!
On the other end of the ajax request is a php file that makes a postgresql request.
Much thanks for any ideas!
Take a look at the timeout option (http://api.jquery.com/jQuery.ajax/). You can set it on a particular call, or globally with $.ajaxSetup().
To have the abort button appear after 5 seconds, add a setTimeout function after your call to send. Once the AJAX command is complete, you can add code to clear the timeout and remove the abort button if it exists.
var timeOutID = 0;
$.ajax({
url: 'ajax/test.html',
success: function(data) {
clearTimeOut(timeOutID);
// Remove the abort button if it exists.
}
});
timeOutID = setTimeout(function() {
// Add the abort button here.
}, 5000);
This way the abort button will never appear if AJAX returns quick enough.
Usually, I'll set a timeout once the request is sent that will trigger after 10 seconds or so and then fallback on something else to make sure it still happens (for example, form submission).
So set a variable to false, var failed = false; and do the request
At the same time that the request starts, set a timeout:
setTimeout(function() {
failed = true;
$("#form").submit();
return false;
}, 10000);
In the return function of the ajax call, check to see if the failed variable has been set to true, and if it has, don't actually do whatever it was originally trying, otherwise it could mess something up, or confuse the user if something else is happening (since these things usually happen on slower internet connections, if the next step appears while a new page is loading, they might try to interact and then the page will change).
$.post("ajaxcall.php", {'etc': "etc"},
function(returned) {
if (failed != true) {
//do whatever with returned variable
}
});
var timer = 0,
XHR = $.ajax({
url: 'ajax/mypage.html',
beforeSend: function() {
timer=setTimeout(showAbort, 5000);
}
});
function showAbort() {
$('<input type="button" value="Abort" id="abort_button"/>').appendTo('#some_parent');
$('#abort_button').on('click', function() {
XHR.abort(); //abort the Ajax call
});
}
XHR.always(function() { //fires on both fail and done
clearTimeout(timer);
if ($('#abort_button').length) {
$('#abort_button').remove(); //remove button if exists
}
});

Categories

Resources