I have a python script that's doing around 8 or 9 specific steps. These steps are being logged in a file. For web GUI to display status change, or error messages, I am using the script belowjquery PeriodicalUpdater plugin.
I need the program to run simultaneously so that as the value in the file changes,it gets polled and displayed.
Please find my jquery code below.
Note the url "/primary_call/" takes around 2 and half minutes to execute. Problem is async :false is not working. The browser waits for 2.5 minutes, and then gets into the next level.
I tried in Firefox and Chrome and it gives the same result.
When I call the URL of another browser tab, it works perfectly, but I am unable to run both script components simultaneously, when I try calling from the same page.
What should I do so that the browser initiates "/primary_call/", which runs a Python script in the background, at the same time moving ahead to the portion called PeriodicUpdate.
$(document).ready(function()
$.ajax({
type: 'GET', // Or any other HTTP Verb (Method)
url: '/primary_call/',
async: false,
success: function(r){
return false;
},
error: function(e){
}
});
$.PeriodicalUpdater({
url : '/static/12.txt',
method: 'post',
maxTimeout: 6000,
},
function(data){
var myHtml = data + ' <br />';
$('#results').append(myHtml);
});
})
Setting async:false means you are making the process synchronous, so the browser will hang on it until it is finished -- it can't move on to your other method. Removing that option will make the call asynchronous (which it is by default, as it should be) at which point the browser will initialize each ajax call in a separate thread.
In short, remove async:false.
Related
I need to perform semi-continuous AJAX requests to display data based on the latest entry into a DB. This all works fine with a setInterval() but now I notice the continuously increasing number of resources and size in the Web Inspector (see image). I imagine that this may become an issue if the app is open for long periods of time? Or is the size displayed (1) merely network activity? How could I prevent this? I have set the jQuery ajax cache to false.
Update:
Did not post any code because there's nothing special there. Just a basic jQuery ajax function, php script that queries DB based on data from the ajax function and echoes it back in a response.
So is the number of KB in the Web Inspector (1) network traffic or cached?
$(document).ready(function(){
setInterval(refresh, 2000);
})
function refresh(){
$.ajax({
type: "POST",
cache: false,
url: "../update.php",
data: dataString,
success: function(msg){
if(msg2 == 'same'){
// do nothing
}else{
$('#result').html(msg);
}
}
})
}
I have a script that runs a long conversion php script and a progress polling script. After looking at several posts about this subject i found that it should be possible to use async ajax calls combined with timeout from javascript to create a construction that would poll the progress regularly and update my page with a percentile number. See code below
function startExcelConversion(excelname){
var poll = function(){
setTimeout(function(){
$.ajax({
url: "../include/ajax/ajax.php?action=poll_progress",
success: function(data){
//Update the progress bar
// show progress
console.log('progresser: '+data);
$("#progress").val(data);
//Setup the next poll recursively
poll();
},
complete: function( jqXHR, textStatus ){
//Update the progress bar
// show progress
console.log(textStatus);
},
dataType: "json"
});
}, 3000);
};
poll();
//show loading image
console.log('starting conversion');
$('#progress').val("Excel openen...");
$('#main').prepend('<img id="loading" src="../include/image/load.gif">');
$("#loading").show();
$.ajax({
url: '../import/import_main.php?clean&action=importexcel&excelname='+excelname,
success: function(data) {
console.log(data);
$("#main").html(data)
$('#loading').hide();
}
});
return false;
}
the first block launches the script that runs a while (excel reading and conversion).This script updates a database table every 10 rows to set the progress. the second block (from start polling onwards0 should launch a php script that reads this progress db field and echo it so i can update my input field with the percentile. However the polling script is not called during the runtime of the first php script (import_main.php). I tried $.post and $.get calls (which should as $.ajax be asynchronous by default). Also tried setInterval but that did not work and was not recommended due to timing problems. Am i missing something obvious here or is it a setting in php i am missing?
thnx in advance
I would try to define poll at the top of the script, like:
var poll = function(){
setTimeout(function(){
$.ajax({
url: "../include/ajax/ajax.php?action=poll_progress",
success: function(data){
//Update the progress bar
// show progress
console.log('progresser: '+data);
$("#progress").val(data);
//Setup the next poll recursively
poll();
},
dataType: "json"
});
}, 3000);
});
and then call it, like, poll(), after the ajax call. See if that helps. Right now, you have an anonymous function after the ajax call, but it tries to call itself with poll(); in the success callback, which isn't going to be defined.
it turned out the problem was threefold:
The first problem was indeed the use of an IIFE function that was not defined at runtime. So using inline function such as z416175 described was certainly valid
The second problem was that when a session is active in PHP it will block other (ajax) calls to prevent session overwriting. So using session_write_close() before entering the long running script worked to allow asynchronous ajax calls for progress updating. See this post (thnx to z416175) One ajax call block other ajax call
The third problem was that when you use xdebug the second problem remains because xdebug keeps a session open preventing the asynchronous ajax progress update call. So be aware when testing that xdebug causes problems with this
Thanks for all input. I have credited z416175's post for various usefull info in his answer and comments
I am attempting to interface with the Google Maps API marking locations based on latitude and longitude data. I would also like to get time zone information based off of this latitude and longitude. To do this, I am using another external API that takes in the latitude and longitude and returns the time off-set. My issue, however, is that this time data returns after the page is loaded.
What is the best way to then add this information to the page after the page has loaded for the user? I started out thinking about using postback, but after doing some research, I don't think that's the right method for my problem.
In browsers, JavaScript allows you to contact a server after a page is loaded. This is known as an asynchronous request, the first 'A' in 'AJAX' (Asynchronous Java and XML).
The X can be a bit of a misnomer, as people will happily pass whole chunks of HTML, or JSON (AJAJ?) or other forms of data instead of XML through this mechanism.
I would always use a framework (my personal choice being JQuery) to perform the operation, as the framework writers will have done the job of making it all work cross-browser for you.
You could use this:
http://api.jquery.com/jQuery.get/
or if the return data is JSON,
http://api.jquery.com/jQuery.getJSON/
This function, part of JQuery, will execute a callback function once the data is loaded. Your callback function can then use the JQuery selectors to find and update the elements in question.
If you update your question with specific code examples I can be more specific with my response.
Edit after seeing code example:
It looks like your problem is actually one of working out the order of code execution. Your code follows this pattern (somewhat simplified and a touch rearranged):
var startTimeZone;
jQuery(document).ready(function($) {
$.ajax({
url: "http://www.worldweatheronline.com/feed/tz.ashx?key=SecretKey&q=" + start_locale + "&format=json",
dataType: "jsonp",
success: function(parsed_json) {
startTimeZone = parsed_json.data.time_zone[0].utcOffset;
console.log("Callback: " + startTimeZone);
},
error: function(parsed_json) {
}
});
});
console.log("Main:" + startTimeZone);
Firstly, there isn't a need to wrap the ajax command in the document ready callback - that only needs to be done once for the whole of your code, around wherever the entry point is. (I assume that it was an attempt to delay the execution until after the following code.) (There is more to learn here as well - JQuery gives you more than one event to help initialise your code and work with the DOM, see window.onload vs $(document).ready() for a brief description)
If you ran the snippet above, you'd find that the console log would probably show:
Main: Undefined
Callback: [StartTimeZone]
where [StartTimezone] is the response from the server. The ajax command is asynchronous, meaning it goes off and does its thing, taking as long as it needs, leaving the code after it to run as if nothing had happened. When it's finished it calls the 'success' or 'error' callback appropriately. So the 'main' console log is called before the variable has been defined. After that, the callback is hit by the response to the ajax call - so the StartTimeZone is output.
If you're new to callbacks or used to a language that doesn't support them or use them very often (like PHP), you may expect or want the code to pause at the ajax call, then run the callback, then carry on with the rest of the code. Obviously this isn't the case.
In this simple situation I would simply move the code to process the timezone into the callback, but your code has a further wrinkle - you need two values, which you seem to need to retrieve with separate calls.
In this case, we need to make sure we have both values before we run the code that uses them. How can we do this?
A simple solution would be:
var startTimeZone;
var endTimeZone;
$.ajax({
url: "http://www.worldweatheronline.com/feed/tz.ashx?key=SecretKey&q=" + start_locale + "&format=json",
dataType: "jsonp",
success: function(parsed_json) {
startTimeZone = parsed_json.data.time_zone[0].utcOffset;
getEndTimeZone();
},
error: function(parsed_json) {
//console.log("Error: " + parsed_json);
}
});
function getEndTimeZone() {
$.ajax({
url: "http://www.worldweatheronline.com/feed/tz.ashx?key=SecretKey&q=" + end_locale + "&format=json",
dataType: "jsonp",
success: function(parsed_json) {
endTimeZone = parsed_json.data.time_zone[0].utcOffset;
console.log(endTimeZone);
processTimeZones();
},
error: function(parsed_json) {
//console.log("Error: " + parsed_json);
}
});
}
function processTimeZones() {
var timeZoneDifference = (endTimeZone * 3600000) - (startTimeZone * 3600000);
// Do the rest of your processing here
}
Functions aren't run until they are called. Also, functions in JavaScript have access to the variables in their containing scope (this means that the functions have access to startTimeZone and endTimeZone, which are defined outside the functions themselves.)
The code above will call getEndTimeZone on success of the first ajax call. getEndTimeZone then uses an ajax call to get the end time zone, then calls the process function on success. This function definitely has access to the variables you need.
Of course, we're waiting in a queue now for two requests to be processed. We could speed things up a little by calling both at the same time, calling the process function with both, then figuring out if we have the data we need before doing the processing:
var startTimeZone;
var endTimeZone;
$.ajax({
url: "http://www.worldweatheronline.com/feed/tz.ashx?key=SecretKey&q=" + start_locale + "&format=json",
dataType: "jsonp",
success: function(parsed_json) {
startTimeZone = parsed_json.data.time_zone[0].utcOffset;
processTimeZones();
},
error: function(parsed_json) {
//console.log("Error: " + parsed_json);
}
});
$.ajax({
url: "http://www.worldweatheronline.com/feed/tz.ashx?key=SecretKey&q=" + end_locale + "&format=json",
dataType: "jsonp",
success: function(parsed_json) {
endTimeZone = parsed_json.data.time_zone[0].utcOffset;
console.log(endTimeZone);
processTimeZones();
},
error: function(parsed_json) {
//console.log("Error: " + parsed_json);
}
});
function processTimeZones() {
if (startTimeZone != undefined && endTimeZone != undefined)
{
var timeZoneDifference = (endTimeZone * 3600000) - (startTimeZone * 3600000);
// Do the rest of your processing here
}
}
Whichever ajax call returns first will call the process function. However, one of the variables will be undefined so the if condition will fail and the function will silently return. When the second result comes in, both variables will be set. Now the if condition will be met and the processing code will run.
There are 1001 ways to skin the proverbial cat, but these should hopefully get you started using the callbacks effectively.
Of course, all this is ignoring the fact that you've put the ajax calls in a for loop. Things could get funky if each iteration of the processing you need to do is dependent on the order it happens - the ajax calls could return in potentially any order. As you're plotting a route, this may well be the case.
If so, you could split your code into two phases - a loading phase and a processing phase. Run all the callbacks in the loading phase, then when you have all the data move to the processing phase and place the markers on the map. You could store the data in an array of objects.
There are a few ways to detect the end of the loading phase. One would be a counter that you increment every time you make an ajax call and decrement every time you get a success. You'd be able to create a loading progress bar using the same counter.
Also you could display a message to the user if any of the calls failed, with a link to restart the process. (Trivially this would reload the whole page, but you could restart the loading stage.)
HTH. By all means shout if you need further help.
I'd like to preface this with an apology if I'm doing things in a "weird" way, as I'm primarily a C developer and am solving this AJAX problem the way I would in C.
I have a script that will be connecting to a "push server" that waits until a message is available, then sends only that one message and breaks the connection. The client must then reestablish the connection to listen for future messages.
I tried to do this by implementing a synchronous AJAX call within an asynchronous callback, and it works except it appears the DOM (maybe? I'm showing my ignorance of JS here) will block until all calls are complete.
I do not know how to do it with purely asynchronous calls as I do not want to end up exhausting the stack by having a callback calling a callback each time.
This is the code:
$.ajax({
url: './recoverDevice',
data: JSON.stringify(requestData),
dataType: 'json',
type: 'POST',
success: function(j)
{
console.log(j);
if (j.success)
{
//Indefinitely listen for push messages from the server
var loopMore = true;
while(loopMore)
{
$.ajax({
async: false,
url: './getPendingMessage',
dataType: 'json',
type: 'POST',
success: function(j)
{
//alert(j.message);
$("#progressBox").append("<li>" + j.message + "</li>");
loopMore = !j.complete;
}
});
}
}
else
{
$("#errorBox").show();
$("#errorBox").text(j.errorMessage);
}
}
});
Now, logically, this code should work. Within an asynchronous function, I loop over a synchronous JS call, each time I get a message I will append it to the DOM, and only when the server tells me there will be no more messages do I exit the loop, ending the asynchronous thread and completing the task.
The problem is that the DOM access appears to be all coalesced once all messages have been received. i.e. the appends only happen once all messages have been received and the asynchronous thread has exited.
The commented out alert was a test - it works perfectly. I get a message box after each and every notification, and it pauses correctly until the next message (with the rest of the code as-is).
I'm guessing this is my browser (Chrome) doing some magic to protect against race conditions by not allowing DOM manipulation until the asynchronous thread has exited? Or am I way off the mark and barking up the wrong tree here?
Getting rid of the loop and setting async to true makes the first message be received properly (no problems there), but obviously no messages thereafter.
Obviously I could do something like this:
function GetMessage()
{
$.ajax({
async: true,
url: './getPendingMessage',
dataType: 'json',
type: 'POST',
success: function(j)
{
$("#progressBox").append("<li>" + j.message + "</li>");
if (!j.complete)
{
GetMessage();
}
}
});
}
But that would result in a stack overflow over time (no?).
An obvious solution would be to use asynchronous calls here too, but to signal a while loop to pause and continue with new calls via some sort of synchronization primitives, but appears that JS does not have signalling primitives?
Figured this one out - I don't know why I didn't see this before but my latter code fragment works perfectly. I didn't realize it at the time of posting, but it can't overflow the stack because each time it runs it launches an async call and exits - so the stack frame is never more than 2 or 3 deep. The asynchronous calls are managed externally and won't be on the stack, so each time it starts over.
I'd still appreciate any input on why the first method (synchronous code in asynchronous call) didn't/wouldn't work.
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("?");
}
});
}