Stop javascript function if not finished within 5 seconds (jquery) - javascript

I currently use several APIs to pull data from other sites. However, sometimes the APIs are incredibly slow (especially Twitter) and the script will continue to run perpetually because Twitter never responds.
My question is how can I tell the function to stop IF and ONLY IF it hasn't completed in x number of seconds? I'm assuming this has something to do with setTimeout(), but I can't figure it out.
Here's some example code from the Yahoo Weather API:
<script type="text/javascript">
$(function() {
$.simpleWeather({
zipcode: '<?= $property_zip ?>',
unit: 'f',
success: function(weather) {
//success
},
error: function(error) {
$("#weathercontent").html('<p>'+error+'</p>');
}
});
});
</script>
Thanks,
Phil

You could set a global timeout for all jQuery AJAX requests to 5 seconds. I believe this also covers JSONP requests since jQuery 1.5, but it may be worth investigating.
You could setup a single handler where timeout is set. It could be based on the URL of the outgoing request. So maybe for all calls to Yahoo, or Flickr, or Twitter, you can set a timeout. The pre-filter below would run before each AJAX request is sent, and gets a chance to modify the request fully before it is sent.
jQuery.ajaxPrefilter(function(options) {
if (options.url is not going to my server) { // pseudocode :)
options.timeout = 5000;
}
});
If you don't want a global handler, then set the timeout property in each $.ajax({ .. }) call you are making. This could be problematic for 3rd-party plugins such as simpleWeather which you'll have to modify the source for if setting the timeout explicitly.

Do you mean how can you cancel the ajax request if the server response is slow? I believe it's myAjaxRequest.abort(). This is not that same thing as stopping a function mid-execution. I'm not sure there's a way to do that.

Related

Ajax calls DURING another Ajax call to receive server's task calculation status and display it to the client as a progression bar

I'm trying to figure out if there's any chance to receive the status of completion of a task (triggered via an ajax call), via multiple (time intervalled) ajax calls.
Basically, during the execution of something that could take long, I want to populate some variable and return it's value when asked.
Server code looks like this:
function setTask($total,$current){
$this->task['total'] = $total;
$this->task['current'] = $current;
}
function setEmptyTask(){
$this->task = [];
}
function getTaskPercentage(){
return ($this->task['current'] * 100) / $this->task['total'];
}
function actionGetTask(){
if (Yii::$app->request->isAjax) {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return [
'percentage' => $this->getTaskPercentage(),
];
}
}
Let's say I'm in a for loop, and I know how many times I iterate over:
function actionExportAll(){
$size = sizeof($array);
$c = 0;
foreach($array as $a){
// do something that takes relatively long
$this->setTask($size,$c++);
}
}
While in the client side i have this:
function exportAll(){
var intervalId = setInterval(function(){
$.ajax({
url: '/get-task',
type: 'post',
success: function(data){
console.log(data);
}
});
},3000);
$.ajax({
url: '/export-all',
type: 'post',
success: function(data){
clearInterval(intervalId); // cancel setInterval
// ..
}
});
}
This looks like it could work, besides the fact that ajax calls done in the setInterval function are completed after "export-all" is done and goes in the success callback.
There's surely something that I'm missing in this logic.
Thanks
The problem is probably in sessions.
Let's take a look what is going on.
The request to /export-all is send by browser.
App on server calls session_start() that opens the session file and locks access to it.
The app begins the expensive operations.
In browser the set interval passes and browser send request to /get-task.
App on server tries to handle the /get-task request and calls session_start(). It is blocked and has to wait for /export-all request to finish.
The expensive operations of /export-all are finished and the response is send to browser.
The session file is unlocked and /get-task request can finally continue past session_start(). Meanwhile browser have recieved /export-all response and executes the success callback for it.
The /get-task request is finished and response is send to browser.
The browser recieves /get-task response and executes its success callback.
The best way to deal with it is avoid running the expensive tasks directly from requests executed by user's browser.
Your export-all action should only plan the task for execution. Then the task itself can be executed by some cron action or some worker in background. And the /get-task can check its progress and trigger the final actions when the task is finished.
You should take look at yiisoft/yii2-queue extension. This extension allows you to create jobs, enqueue them and run the jobs from queue by cron task or by running a daemon that will listen for tasks and execute them as they come.
Without trying to dive into your code, which I don't have time to do, I'll say that the essential process looks like this:
Your first AJAX call is "to schedule the unit of work ... somehow." The result of this call is to indicate success and to hand back some kind of nonce, or token, which uniquely identifies the request. This does not necessarily indicate that processing has begun, only that the request to start it has been accepted.
Your next calls request "progress," and provide the nonce given in step #1 as the means to refer to it. The immediate response is the status at this time.
Presumably, you also have some kind of call to retrieve (and remove) the completed request. The same nonce is once again used to refer to it. The immediate response is that the results are returned to you and the nonce is cancelled.
Obviously, you must have some client-side way to remember the nonce(s). "Sessions" are the most-common way to do that. "Local storage," in a suitably-recent web browser, can also be used.
Also note ... as an important clarification ... that the title to your post does not match what's happening: one AJAX call isn't happening "during" another AJAX call. All of the AJAX calls return immediately. But, all of them refer (by means of nonces) to a long-running unit of work that is being carried out by some other appropriate means.
(By the way, there are many existing "workflow managers" and "batch processing systems" out there, open-source on Github, Sourceforge, and other such places. Be sure that you're not re-inventing what someone else has already perfected! "Actum Ne Agas: Do Not Do A Thing Already Done." Take a few minutes to look around and see if there's something already out there that you can just steal.)
So basically I found the solution for this very problem by myself.
What you need to do is to replace the above server side's code into this:
function setTask($total,$current){
$_SESSION['task']['total'] = $total;
$_SESSION['task']['current'] = $current;
session_write_close();
}
function setEmptyTask(){
$_SESSION['task'] = [];
session_write_close();
}
function getTaskPercentage(){
return ($_SESSION['task']['current'] * 100) / $_SESSION['task']['total'];
}
function actionGetTask(){
if (Yii::$app->request->isAjax) {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return [
'percentage' => $this->getTaskPercentage(),
];
}
}
This works, but I'm not completely sure if is a good practice.
From what I can tell, it seems like it frees access to the $_SESSION variable and makes it readable by another session (ence my actionGetTask()) during the execution of the actionExportAll() session.
Maybe somebody could integrate this answer and tell more about it.
Thanks for the answers, I will certainly dig more in those approaches and maybe try to make this same task in a better, more elegant and logic way.

Ajax call stops after a certain amount of PHP loops (2 minutes)

I have a button that checks a lot (300+) posts for a specific value and other things (about 20 if, else's). Somehow the ajax call of the button stops after looping about 73 times/2mins.
It doesn't loop this ajax call, there's a PHP loop in the function it's referring to.
Is there any way to extend this? This is what I currently have:
$.ajax({
url: ajaxurl + "?action=updatefield",
type: 'post',
data: dataString,
success: function(data) {
console.log("SUCCESS!");
$("#myResponse").html("<h4>Response: </h4><hr>" + data);
},
error: function(data) {
console.log("FAILURE");
},
timeout: 600000 // (this is what I tried, but it doesn't seem to work)
});
Perhaps this is the answer for my problem, but not my question: Browser Timeouts
Is there a way to extend this time, or is there another way?
So let me get this right... you have ONE Ajax call that triggers a PHP loop, and it's the PHP loop that times out?
It could be:
An HTTP timeout (this can be increased in the Apache config, but it's not recommended)
An HTTP body size overflow (again this can be increased in the Apache config, but it's not recommended)
A server-side limit on the maximum execution time of a PHP script (this can be changed in php.ini, but guess what... it's not recommended!)
Ultimately you are not doing this right. You should be calling the PHP script every so often (for example every second) by putting the Ajax call in a JS setInterval(1000); The PHP script itself should be quick and to the point.
I have tracked down the issue by enabling PHP errors. Besides fixing common errors, I found the issue.
Allowed memory size of 134217728 bytes exhausted
I'm currently trying to clean up my code and remove any unnecessary requests to increase speed and efficiency. Thanks for all the answers.

setInterval() not stopping on time, "jumping" between intervals

I'm building a web app to help with a restaurant, and my client was very clear on that he wanted the app to be asynchronous.
During localhost development I used setInterval to update the page periodicaly using variations of this code for each button:
$('#showWaitlist').click(function(){
showWaitlist();
stopUpdate(interval);
interval = setInterval(function() { showWaitlist();}, intervalTime);
});
function stopUpdate(){
clearInterval(interval);
}
So that every time I click a button it stops the past interval and starts it's own.
It worked fine, however, when I moved the app to the server the intevals would sometimes overlap each other, specially when the server was on heavier-than-avarage load or when I used a phone to access the site.
If setInterval and stopUpdate are js shouldn't they work on clientside and be practically instant? What could cause this "jumping" between intervals?
This is a link to the website: http://www.emc2.mx/Pruebas/unicenta/PostodoroApp/
Please note that the problem not always happens, but you can probably replicate it if you opne it on your phone.
I'll add showWaitlist here, but I doubt there's something wrong with it.
function showWaitlist(){
$.ajax({
type:'GET',
url: 'waitlist.php',
dataType: 'html',
success: function(result){
$('#result_table').html(result);
} // End of success function of ajax form
}); // End of ajax call
}
You will need to clear the interval in
the success of the ajax call on your code by adding the following line
clearInterval(interval); // stop the timer once the time finishes.
after the following line
$('#result_table').html(result);
You need to have access of the interval variable in the success method callback

Detect when an AJAX request starts

Following the spec I've been given for this particular item, I have a few dozen AJAX requests all initiated at the same time, and the results displayed as they complete to give responses as soon as possible.
Currently I have all of the items show as "Loading...", then gradually getting replaced as the requests complete.
Due to limitations placed by the browser, only about five of them actually load at any given time, the others are blocked until earlier ones have completed.
I'd like to know if there's any way of finding out when the block ends and the request is actually sent.
Initial tests using onreadystatechange to detect readyState values other than 4 are not promising - no event is fired until it's complete, at which point I get 2, 3 and 4 in immediate succession (note that for testing, the AJAX responses are artificially delayed by usleeping for a random time)
Any ideas? Or is my only real option to manually implement the blocking part?
The best approximation of this you can actually get is to watch for readyState "1".. which signifies the server connection has been established. This will give you a pretty close estimation as to when the connection actually went live.
I've hacked up at http://jsfiddle.net/r0gknr3w/. Just watch the JS console, and you'll see "1" logged. You say you never saw a readyState 1... but it's definitely there.
var xhr = $.ajax({
url: "/echo/html",
xhr: function () {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
console.log(xhr.readyState);
}
return xhr;
}
});
Can you use jquery function to call ajax request.It is better to send multiple request parallel and response get as soon as..

Why does my spinner GIF stop while jQuery ajax call is running?

I'm just starting to wean myself from ASP.NET UpdatePanels. I'm using jQuery and jTemplates to bind the results of a web service to a grid, and everything works fine.
Here's the thing: I'm trying to show a spinner GIF while the table is being refreshed (à la UpdateProgress in ASP.NET) I've got it all working, except that the spinner is frozen. To see what's going on, I've tried moving the spinner out from the update progress div and out on the page where I can see it the whole time. It spins and spins until the refresh starts, and stays frozen until the refresh is done, and then starts spinning again. Not really what you want from a 'please wait' spinner!
This is in IE7 - haven't had a chance to test in other browsers yet. Any thoughts? Is the ajax call or the client-side databinding so resource-intensive that the browser is unable to tend to its animated GIFs?
Update
Here's the code that refreshes the grid. Not sure if this is synchronous or asynchronous.
updateConcessions = function(e) {
$.ajax({
type: "POST",
url: "Concessions.aspx/GetConcessions",
data: "{'Countries':'ga'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
applyTemplate(msg);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
}
});
}
applyTemplate = function(msg) {
$('div#TemplateTarget').setTemplate($('div#TemplateSource').html());
$('div#TemplateTarget').processTemplate(msg);
}
Update 2
I just checked the jQuery documentation and the $.ajax() method is asynchronous by default. Just for kicks I added this
$.ajax({
async: true,
...
and it didn't make any difference.
It's not the Ajax call that's freezing the browser. It's the success handler (applyTemplate). Inserting HTML into a document like that can freeze IE, depending on how much HTML there is. It's because the IE UI is single threaded; if you notice, the actual IE menus are frozen too while this is happening.
As a test, try:
applyTemplate = function(msg) {
return;
}
I don't remember precisely what caused it, but we had a similar issue with IE6 in a busy box and we fixed it with this incredible hack in the Javascript:
setTimeout("document.images['BusyImage'].src=document.images['BusyImage'].src",10);
That just sets the image source to what it was before, but it is apparently enough to jostle IE out of its stupor.
edit: I think I remember what was causing this: We were loading the animation into a div with display: none. IE loads it and doesn't start the animation, because it's hidden. Unfortunately it doesn't start the animation when you set the containing block to display: block, so we used the above line of code to trick IE into reloading the image.
The image freezes because while it is hidden the animation is disabled by IE.
To fix this, append the loading image instead of unhiding it:
function showLoader(callback){
$('#wherever').append(
'<img class="waiting" src="/path/to/gif.gif" />'
);
callback();
}
function finishForm(){
var passed = formValidate(document.forms.clientSupportReq);
if(passed)
{
$('input#subm')
.val('Uploading...')
.attr('disabled','disabled');
$('input#res').hide();
}
return passed;
}
$(function(){
// on submit
$('form#formid').submit(function(){
var l = showLoader( function(){
finishForm()
});
if(!l){
$('.waiting').remove();
}
return l;
});
});
Are you sure that its during the AJAX call that the GIF isn't spinning?
In your concessions.aspx place this line somewhere in the handling of GetConcessions:-
System.Threading.Thread.Sleep(5000);
I suspect that the gif spins for 5 seconds then freezes whilst IE renders and paints the result.
I know the question was regarding asynchronous ajax calls. However I wanted to add that I have found the following in my tests regarding synchronous ajax calls:
For Synchronous ajax calls. While the call is in progress (i.e. waiting for the server to respond). For the test i put a delay in the server response on the server.
Firefox 17.0.1 - animated gif continues to animate properly.
Chrome v23 - animated gif stops animation while the request is in progress.
well, this is for many reasons. First at all, when the ajax call back of the server, you will sense a few miliseconds your gif frozen, but not many relevant. After you will start to process information, and depending of the objects that you manipulate and how you do it, you will have more o less time your gif frozen. This is because the thread is busy processing information. Example if you have 1000 objects and your do a order, and move information, and also you use jquery and append, insert, $.each commands, you will senses a gif frozen. Sometimes it's imposible avoid all the frozen gifs, but yu can limit the time to a few miliseconds doing this: Make a list of response ajax, and process it each 2 seconds (with this you will have the results in a alone array and you wil call it with one setInterval and you avoid the bottle neck of try process one response when the before response is still processing). if you use JQuery don't use $.each, use for. Don't use dom manipulation (append,insert,etc..), use html(). In resume do less code, refactor, and procdess all the response (if you did more of 1) like only 1. Sorry for my english.
I had a similar problem with the browser freezing. If you are developing and testing locally, for some reason it freezes the web browser. After uploading my code to a web server it started to work. I hope this helps, because it took me hours to figure it out for myself.
I have seen this behavior in the past when making AJAX calls. I believe this is related to the fact that browsers are only single threaded, so when the AJAX call is returned the thread is working on the call, so consequentially the animated GIF needs to stop momentarily.
dennismonsewicz's answer is greate. Use spin.js and the site http://fgnass.github.com/spin.js/ shows the step which is quite easy.
Under heavy process we should use CSS animations.
No JS driven animations and GIFs should be used becacuse of the single thread limit otherwise the animation will freeze. CSS animations are separated from the UI thread.
Are you doing a synchronous call or asynchronous call? synchronous calls do cause the browser to seemingly lock up for the duration of the call. The other possibility is that the system is very busy doing whatever work it is doing.
Wrapping ajax call in setTimeout function helped me to prevent freezing of gif-animation:
setTimeout(function() {
$.get('/some_link', function (response) {
// some actions
});
}, 0);
Browsers are single-threaded and multi-threaded.
For any browser :
When you a called a function that contains a nested ajax function
java/servlet/jsp/Controller >
keep Thread.sleep(5000); in servlet to understand the async in ajax when
true or false.
function ajaxFn(){
$('#status').html('WAIT... <img id="theImg" src="page-loader.gif" alt="preload" width="30" height="30"/>');
$('#status').css("color","red");
$.ajax({
url:"MyServlet",
method: "POST",
data: { name: $("textarea").val(),
id : $("input[type=text]").val() },
//async: false,
success:function(response){
//alert(response); //response is "welcome to.."
$("#status").text(response);
$('#status').css("color","green");
},
complete:function(x,y){
//alert(y)
},
error:function(){
$("#status").text("?");
}
});
}

Categories

Resources