Add a timeout to load() - javascript

var refreshId_hxlatestposts = setInterval(function() {
var el = $("#hxlatestposts");
var req = $.get("example.php");
el.fadeOut('slow', function () {
req.done(function( data ){
el.html(data).fadeIn('slow');
});
});
}, 60000);
This is what i use to refresh a div every minute, sometimes it gets hung up when the site it is getting the feed from is down or something. I'd like to some how have a timeout so if it cannot load the php file in X seconds then return 'Fail to load'.

jQuery documentation (.ajaxSetup()) suggests using .ajaxSetup() to set the value for timeout, instead of using it in individual requests.
You can use request.fail() to register a function in case of a failed request.
$.ajaxSetup({
timeout: 5000
});
var refreshId_hxlatestposts = setInterval(function() {
var el = $("#hxlatestposts");
var req = $.get("example.php");
el.fadeOut('slow', function() {
req.done(function(data) {
el.html(data).fadeIn('slow');
});
req.fail(function(jqXHR, textStatus) {
el.html('Fail to load').fadeIn('slow');
});
});
}, 60000);

Nice use of deferred objects.
If you replace $.get with $.ajax, you can add a timeout.
var req = $.ajax({
url: "example.php",
type: "GET",
timeout: 5000 // 5 seconds
});
and then add a fail handler
req.done(function(){...}).fail(function(){
alert("failed to load");
});

You'll want to check the status of the incoming response to ensure that the service returned a 200 Ok status. This is more reliable than just waiting for a timeout-- you will know if it's good data or not an can decide to retry by putting your timeout in the complete functions.
$.ajax({
//...
success: function(data, textStatus, xhr) {
console.log(xhr.status);
//handle status codes etc.
// then set your timeout
},
complete: function(xhr, textStatus) {
console.log(xhr.status);
//handle status codes etc.
// then set your timeout
},
// OR
fail: function( xhr, textStatus ){
//retry code or timeout
}
});

jQuery's $.get is just a shorthand for $.ajax, which is used when more flexibility is required (in your case, yes)
Replace $.get("example.php"); with:
$.ajax({
type: "GET",
url: "example.php",
timeout: X*1000,
}).done(function(data) {
el.fadeOut('slow', function () {
el.html(data).fadeIn('slow');
});
}, 60000);
});
where X is number of seconds you would want it to wait (timeout)

Related

Display a specific <div> content at setTimeout()

In the below code I am making an API call to my backend node.js app using setTimeout() which calls my AJAX at every 5 seconds. Inside my AJAX success I am displaying divContent1 & divContent2 based on certain condition which should execute at least once. After that only divContent2 should be visible at each setTimeout() calls.
index.html
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
url: "http://localhost:8070/api/route1",
type: 'POST',
dataType:'json',
success: function(res) {
//Some Task
}
});
$("#myButton").click(function(){
const route2 = function() {
$.ajax({
url: "http://localhost:8070/api/route2",
type: "POST",
dataType: "json",
data: { var1: val1 },
success: function (res) {
// Various tasks
if(res.flag){
$("#divContent1").hide();
$("#divContent2").show();
}
else{
$("#divContent1").show();
}
//Functions that handle div content data
},
beforeSend: function() {
$("#divContent1").hide();
$("#divContent2").hide();
},
complete: function() {
setTimeout(route2,5000);
},
});
};
$(function(){
route2();
})
});
});
</script>
The setTimeout() calls the entire route2 function which handles all the display and insertion of div content. However, the ask is to only display divContent2 from the second call.
Looking for a solution for this
The setTimeout() calls the entire route2 function which handles all
the display and insertion of div content. However, the ask is to only
display divContent2 from the second call.
You're calling route2 recursively with setTimeout(route2,5000); under complete. So this will run infinitely as complete occur each time an ajax call is completed (wether success or error). So what you can do is to create a timer and clear it after the second execution, something like this:
var ctr = 0, timer =0;
const route2 = function() {
$.ajax({
...
success: function (res) {
//Write you logic based on ctr
}
complete: function() {
if(ctr>0){
clearTimeout(timer)
}else{
timer = setTimeout(route2,5000);
ctr = ctr+ 1;
}
},
});
};
Will an external variable be enough? Just define it in the outer context and set/check it to choose the behavior:
// before declaring button click handler
var requestDoneAtLeastOnce = false;
// ...
// somewhere in success handler
success: function (res) {
if (!requestDoneAtLeastOnce) {
requestDoneAtLeastOnce = true;
// do something that belongs only to handling the first response
}
else {
// this is at least the second request, the other set of commands belongs here
}
}

Detecting when ajax success function takes longer than 5 seconds and redirect

Hello I have this script that moves from one page through a href without page load.
It works perfectly, but I want to redirect to the requested page if Ajax takes longer than 5 seconds to respond, usually caused by probably slow internet connection.
In this case: Stop the script and load the page normally.
Firstly the href:
new
New 1
This is the script:
<script>
$(function(){
$("a[rel='tab']").click(function(e){
pageurl = $(this).attr('href'); //get the href clicked
$.ajax({url:pageurl+'?rel=tab',
success: function(data){
$('#mole').html(data);
}
});
if(pageurl!=window.location){
window.history.pushState({
path:pageurl
},'',pageurl);
}
return false;
});
});
$(window).bind('popstate', function(){
$.ajax({
url:location.pathname+'?rel=tab',
success: function(data){
// here how do I detect if the success takes longer than 5 seconds
// stop the script and load the page normally which is the URL parameter in ajax
$('#mole').html(data);
}
});
});
</script>
First, we need to add a timeout to the ajax handler so it will cancel the request after 5 seconds (here we use 5000 for milliseconds). Then, based on the docs, head to error and you can see the second param is textStatus. If it was a timeout, this will be equal to "timeout". This is probably your easiest path to what you need to do. Update the error handler as needed for your functionality.
$(window).bind('popstate', function() {
var url = location.pathname + '?rel=tab';
$.ajax({
timeout: 5000,
url: url,
success: function(data) {
$('#mole').html(data);
},
error: function(jqXHR, textStatus) {
if (textStatus === 'timeout') {
// we know the ajax failed due to a timeout,
// do what you need here, below is an example.
window.location = url;
}
}
});
});

Waiting on jQuery AJAX calls to complete

I have an upload button that when clicking calls an ajax function to upload document. Once that function runs I call another ajax function to refresh a table on screen displaying all my documents. I have been looking at this question - Wait until all jQuery Ajax requests are done?
which would seem to be what I need. However I am un-sure how to implement for my current code. I have:
$("#UploadButton").on('click', function () {
doUpload(); // My First AJAX function
refreshTable(); // My Second AJAX Function
});
My doUpload AJAX function is as below:
function doUpload() {
$.ajax({
url: 'myupload url',
type: 'POST',
data: new FormData($('#uploadForm')[0]),
processData: false,
contentType: false,
success: function () {
$.growlUI('Document Uploaded Sucessfully');
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status + " " + thrownError);
}
});
}
My refreshTable ajax function then is:
function refreshTable() {
$.ajax({
url: 'url to get all files',
type: 'GET',
data: $('#searchForm').serialize(),
success: function (data) { populateTable(data); },
error: function (xhr, ajaxOptions, thrownError) { alert(xhr.status + " " + thrownError); }
});
return false;
}
If I upload a document with current solution the success function of refreshTable seems to get hit too quickly and it doesn't have the find the most recent file uploaded. I had tried to add the call to refreshTable() in the success function of my doUpload with a setTimeout of 5 seconds and sometimes this was working and refreshing the table but other times it wasn't uploading the table.
I then changed the click handler on the button to the below to attempt to have the functionality the other StackOverflow answer I linked to above has but this isn't working either
$("#UploadButton").on('click', function () {
$.when(doUpload()).done(function() {
refreshTable();
});
});
You can use callback mechanism.
function doUpload(callback) {
$.ajax({ //some parameters
success: function (data) {
//do some work here
callback();
}
);
}
Then you can call the function chain as:
doUpload(refreshTable);
EDIT : #qamyoncu answers is better than mine.
In AJAX, calls are done async. that's why you don't get what you want.
Here is a tricky solution to avoid the problem you have:
function doUpload(init) {
var res = null;
var _init = init || false;
if (!_init) {
_init = true;
$.ajax({
/// ajax call for doUpload()...
});
}
if (res == null) {
setTimeout(function(){ doUpload(_init); }, 100);
} else {
refreshTable();
}
}

Rate-limiting AJAX requests for updating content to avoid duplicates

I'm trying to fetch posts dynamically using AJAX and JQuery by checking if the user is close to the bottom. Serverside is in python on GAE.
Listening for scroll:
this.config.window.on('scroll',this.loadContent);
1.Checking for distance from bottom
2.Sending an ajax request with the number of current posts in order to retrieve the next 10
3.results.check = true means that the server has no further posts to send.
loadContent: function(){
// 1
if($(document).height() - $(window).height() - $(window).scrollTop() < 1000) {
var posts = $('.troll').children('div').length;
data = 'loadmore=True&offset=' + posts; //2
$.ajax({
url: '/',
type: 'POST',
data: data,
dataType: 'json',
success: function(results){
if (results.check === 'true'){ //3
$(window).unbind('scroll');
return;
}
Post.insert10Values(results);
}
});
};
},
insert10Values: function(results){
var update = Handlebars.compile($('#troll10').html()),
troll10update = update(results);
$('div.troll').append( troll10update );
}
The problem here is that when scrolling fast, two or more requests are sent to the server and i get duplicate entries. I want to rate-limit on client-side.
Set a flag loading = false. Before you send a request, check the flag. If it's false, set the flag to true and proceed with request, otherwise ignore the event. When results arrive, show them and set the flag back to false.
Part of your problem is scroll event will trigger many times a second
you can throttle any function calls doing something like this:
var scrollTimer=false;
var delay=500; /* 1/2 second*/
$(window).on('scroll',function(){
if( scrollTimer){
clearTimeout( scrollTimer);
}
scrollTimer=setTimeout(function(){
/* run your code here*/
}, delay);
});
As for the ajax you could store a time for last ajax call and set a miniumum difference based on now vs stored time before making a new ajax call
var lastAJAX=Date.now(), AJAXMin=5000;/* 5 seconds*/
function checkAJAXCalls(){
var now=Date.now(), diff=now-lastAJAX;
if( diff >= AJAXMin){
lastAJAX=now;
return true;
}else{
return false;
}
}
Then run if(checkAJAXCalls()) prior to making request. Concept could be modified to update lastAJAX in success callback of $.ajax also
jQuery.ajax has a method called beforeSend. It is executed right before your ajax call. You can use it to check if any other request is in progress and cancel the call if there is one. If you return false in beforeSend function, the ajax call will not be fired so you won't have any duplicate content.
$.ajax({
url: '/',
type: 'POST',
data: data,
dataType: 'json',
beforeSend: function() {
if (window.nextPageProcess) {
return false;
} else {
window.nextPageProcess = 1;
}
},
success: function(results){
if (results.check === 'true'){ //3
$(window).unbind('scroll');
return;
}
Post.insert10Values(results);
window.nextPageProcess = 1;
}
});

Prevent AJAX Queue from blocking browser

Note: simplified example..
I've got a page with 1000 table rows. For each row, i need to "do some work" on the server via an AJAX call, then in the callback, update that table row saying done.
Initially i tried just firing off the 1000 ajax requests inside the .each selector, but the browser was locking up.
So i changed it to try and use an internal ajax counter, so only ever fire off 50 at a time.
Here's the code:
$('#do').click(function () {
var maxAjaxRequests = 50;
var ajaxRequests = 0;
var doneCounter = 0;
var toDo = $('#mytable tr').length;
$.each($('#mytable > tr'), function (i, v) {
while (doneCounter < toDo) {
if (ajaxRequests <= maxAjaxRequests) {
ajaxRequests++;
doAsyncStuff($(this), function () {
ajaxRequests--;
doneCounter++;
});
} else {
setTimeout(function() {
}, 1000);
}
}
});
});
function doAsyncStuff(tr, completeCallback) {
$.ajax({
url: '/somewhere',
type: 'POST',
dataType: 'json',
data: null,
contentType: 'application/json; charset=utf-8',
complete: function () {
completeCallback();
},
success: function (json) {
// update ui.
},
error: function (xmlHttpRequest, textStatus, errorThrown) {
// update ui.
}
});
}
But the browser is still being locked up. It never goes into the $.ajax complete callback, even though i can see the request coming back successfully (via Fiddler). Therefore its just sleeping, looping, sleeping, etc because the callback is never returned.
I've got a feeling that the entire doAsyncStuff function needs to be asynchronous?
Any ideas on what i am doing wrong (or how i can do this better)?
You are doing a while loop inside the .each callback function, so there is much more ajax request than 1000, the worst is 1000*1000.
You could delay each ajax request with different time.
$('#do').click(function () {
$('#mytable > tr').each(function (i, v) {
var $this = $(this);
setTimeout(function () {
doAsyncStuff($this, function () {
console.log('complete!');
});
}, i * 10);
});
});
The browser gets locked because of the WHILE... You are creating an endless loop.
The while loops runs over and over waiting for the doneCounter to be increased, but the javascript engine cannot execute the success call of the ajax since it is stuck in the while...
var callQueue = new Array();
$('#mytable > tr').each(function(key,elem){callQueue.push($(this));});
var asyncPageLoad = function(){
var tr = callQueue.splice(0,1);
$.ajax({
url: '/somewhere',
type: 'POST',
dataType: 'json',
data: null,
contentType: 'application/json; charset=utf-8',
complete: function () {
completeCallback();
asyncPageLoad();
},
success: function (json) {
// update ui.
},
error: function (xmlHttpRequest, textStatus, errorThrown) {
// update ui.
}
}
};
asyncPageLoad();
This will call the requests one by one. If you want, simply do a for() loop inside to make maybe 5 calls? And increase the amount if the browser is fine.
Actually, I prefer to send new request when current request is done. I used this method to dump db tables (in this work). Maybe it gives an idea.
See this link, check all check boxes and click Dump! button. And you can find the source codes here (see dumpAll function).

Categories