the below code if the ajax call i make to my run.py and then displays the output in a html tag. the script run.py runs for over 2 mins. But in the js script below. as soon as the script has begun to run. the output ( initial lines of the output) will be displayed in the html tag. the remaining part of the script won't be displayed.
$(document).ready(function(){
$(sub).click(function(){
alert("connecting to host")
$.ajax({
type:'POST',
url:'/cgi-bin/run.py',
dataType: 'html',
success:function (z) {
$('#output').html(z);
}
});
}) ;
});
I'd like to know if there is any function in ajax to wait till completion of script (Not just execution of script. but wait till end ) and then display entire output to the html tag.
Here is my python script:
import sys, os
import cgi, cgitb
def __init__(self, address, username, password):
# connects to host
def sendShell(self, command):
#opens shell
def process(self):
while self.shell.recv_ready():
info += self.shell.recv(1024)
output = str(info, "utf8")
print(output)
hostname = "z.com"
password = "yyy"
username = "dd"
connection = ssh(hostname, username, password)
connection.openShell()
connection.sendShell("date");
jQuery.ajax() has an option async: false, however I'd advise against it and just do whatever you need in ajax callbacks. Also, it's deprecated.
Changing the async flag of the $.Ajax function to false is almost correct, yet in your case the script needs to run for long time so you need to consider using Long Polling for such a request.
The reason is because the browsers have max timeout for ajax calls and usually is set to 1 min depending on the browser(so in your case after 1 min the client / browser stops the connection and wants the response, but you want it to wait until its done and only then send the response back).
So to overcome this you will have to send once a 20 sec or once of the max timeout another request to the py script to check if its done.
Code snippet for javascript side:
function isDone(timestamp) {
timestamp = timestamp || null;
$.ajax({
type:'POST',
url:'/cgi-bin/run.py',
dataType: 'json',
data: { "timestamp": timestamp },
timeout: 20000, // Or to whatever the max-timeout is, haven't checked that with jQuery.
success: function (response) {
if (response.done === false) {
isDone(Date.now ());
} else {
// got the results, can continue.
$('#output').html(response.output);
}
}
});
}
isDone();
I'm not sure how the pyton script should look like, if you want you can share it with me and I will try to complete the server side.
Basically what you should do there is to set the timeout of the script to the max, and return the correct response to the client.
JSON response should look like this:
{
"done": true, // or false if the script timed out.
"output": html, // the variable that should contain the output when the py script is done, if its not done just send a null or don't send it back to the client at all.
"timestamp": time.time() // if im not wrong that's how you get timestamp in py
}
Server-side in pseudo code:
Dynamcally or under setting, configure python script execution time to max or rather to 3 min, sense you mentioned it takes 2 min.
if (timestamp === null) { // first ajax call to this script.
- Start long processing task.
- Write the output to a file.
}
do { // check this code block every 1 sec
if (the file you are writing to was created and is complete / unlocked) {
- Read from that file the content, save it into a variable and delete the file from your system.
- Output the above mentioned response with done set to true and the current timestamp.
- Break outside of the loop
}
if (timed out) { // basically check if 20 second passed sense starting timestamp.
- Output the above mentioned response with done set to false and the current timestamp.
- Break outside of the loop.
}
sleep for 1 sec, you don't want to kill your CPU usage.
} while (true)
Is there a way I can make a progress bar for ajax using jquery using post data (QUERIES) and not uploading a file?
Because the ProgressEvent.lengthComputable read-only property is a Boolean flag indicating if the resource concerned by the ProgressEvent has a length that can be calculated.
If not, the ProgressEvent.total property has no significant value. So my problem is I use ajax for long process queries and not for uploading file. Thanks.
Hi from what i understand, you have a long process running on server that you call using XHR, now you want to show a progress bar in the browser.
Short answer
Not possible in ajax
Long answer
Ajax is just same as http request and there is no way to know the status of the request on server . Only the final output and http status code is available.
Solution
What you want is web sockets and not ajax. WS are bi directional communication standards. On server you can keep publishing the status of the request into the web socket. On client side read from web socket and display the changes.
So overall you need a WS server. Send request from client using websocket and finally keep reading websocket for status till you get the results.
Is this complication needed
Although this is very long and tedious job i know that some projects need it if they have long tasks. Another alternative that you can have is push the task into celery and use XHR poling to get the status of the job.
Hope this helps
In an AJAX request you do not know the response duration on the time you execute the call.
A solution might be to set a timeout limit for the ajax call and animate a progress bar depending on this time. Of course the response will be available before this time limit (at least that's what we want). In this case, force the progress bar to complete it's animation and proceed with your data manipulation.
EXAMPLE
HTML
<!-- LOADER -->
<div id="loader"></div>
jQuery
/**
* Execute ajax request and initialize loader animation
* #param time {number} The ajax timeout limit and progress bar animation duration
*/
function executeAjax(time) {
// Start progress bar initialization
$('#loader').animate({ 'width', '100%' }, time);
// Execute ajax call
$.ajax({
url: '...',
method: 'POST',
data: { ... },
dataType: 'json',
success: function(data) {
// Stop previous animation and start a new one with 0.5 sec duration
$('#loader').stop().animate({ 'width', '100%' }, 500)
.queue(function() {
// Handle the response data here
$(this).dequeue();
});
},
error: function(jqXHR, errorType) {
alert('Error: ' + errorType);
},
timeout: time
});
}
// Call the function passing a timeout of 10 seconds
executeAjax(10000);
I have a webpage that calls an AJAX script - ajax.php. I am using JQuery to send the AJAX requests.
The script ajax.php receives some arguments via$_REQUEST, based on that it starts its processing. The processing has multiple steps involved and at the end of the each step I want to send some feedback back to the page - for example:
Step 1 completed
Step 2 completed
....
Once all the steps are completed - the script ajax.php will output a TXT file which I am outputting via:
header('Content-type: text/plain');
header('Content-Disposition: attachment; filename="output.txt"');
My questions are:
I have a div in the page where I want to show the user that Step 1 completed, Step 2 completed, ... If I use JQuery.ajax(), will the .done function called multiple times? If no, whats the best way to handle it? Can I use ob_implicit_flush in PHP to send 'Step x completed 'messages?
Finally, how will I handle the output of .txt file so that user's browser downloads it? I don't want to save the file on the server and then going into hassle of server disk space, cron jobs of deletes, etc.
I have the option of doing multiple AJAX requests - but again I don't want to do this as this will make my code logic pretty complex and I will have to save a lot of data in $_SESSION to be visible across requests which is again something that I don't want to do.
After your AJAX call to kick off your process, you could make another AJAX call in a loop which requests, returns, and presents the current percentage complete until it reaches 100%. Basically, one AJAX call to initiate the process and then a series of calls which check status.
Here is some simple JavaScript to achieve what you want:
<script>
function startProcess() {
//start your long-running process
$.ajax({
type: 'GET',
url: "/longRunningProcess",
async: true,
success:function (data) {
//do something - your long process is finished
}
});
}
function getStatus() {
//check your progress
$.ajax({
type: 'GET',
url: "/checkProgress",
async: true,
success:function (data) {
//assume the data returned in the percentage complete
var percentage = parseInt(data);
//write your status somewhere, like a jQuery progress bar?
if (percentage < 100) {
//if not complete, check again
getStatus();
}
}
});
}
</script>
Building a social network, I'm trying to fetch live notifications. Currently, the site sends an AJAX request every few seconds using setInterval. It looks something like this:
setInterval ( function(){
url = base_dir+"/ajax/file.php";
data = "data=someData";
$.ajax({
type: "POST",
url: url,
data: data,
dataType: "json",
beforeSend: function(x) {
if(x && x.overrideMimeType) {
x.overrideMimeType("application/json;charset=UTF-8");
}
},
success: function(JSON){
// retrieve data here
}
});
}, 5000);
That works perfectly, but I'm very worried about that creating servers overload. I tried the comet technique but for some reason it sends much more requests than the above code.
Is there any other more useful technique for pushing this data live?
EDIT:
For implementing long polling I used the following (used the example mentioned here: http://techoctave.com/c7/posts/60-simple-long-polling-example-with-javascript-and-jquery):
(function poll(){
url = base_dir+"/ajax/file.php";
data = "data=someData";
$.ajax({
type: "POST",
url: url,
data: data,
dataType: "json",
beforeSend: function(x) {
if(x && x.overrideMimeType) {
x.overrideMimeType("application/json;charset=UTF-8");
}
},
success: function(JSON){
// retrieve data here
},
complete: poll,
timeout: 5000
});
})();
There's a possibility that I might not get the comet principle right.
PHP code:
// Checks for new notifications, and updates the title and notifications bar if there are any
private static function NotificationsCounter (){
//self::$it_user_id = query that retrieves my id for further checks;
//$friend_requests_count = query that retrieves the friend requests count;
//$updates_count = query that retrieves the updates count;
$total_notifications = $friend_requests_count+$updates_count;
if ($total_notifications > 0) $addToTitle = "(".$total_notifications.")";
else $addToTitle = "";
if ($updates_count > 0) $counterHTML = "<span class='notification_counter' id='updates_counter' style='float: right;'>".$updates_count."</span>";
else $counterHTML = "";
$data = array("counter"=>$total_notifications,"addToTitle"=>$addToTitle,"counterHTML"=>$counterHTML,);
echo json_encode($data); // parse to json and print
}
Since Facebook uses PHP as well, how do they do it?
You should use websockets. You can connect to the server and register onmessage handler. Whenever the server has anything to be send to client, your handler will get invoked. No timeout needed.
Check for websocket support in your browser. As of now, only Chrome, Opera and Safari support them.
if ('WebSocket' in window){
/* WebSocket is supported. You can proceed with your code*/
} else {
/*WebSockets are not supported. Try a fallback method like long-polling etc*/
}
Connecting
var connection = new WebSocket('ws://example.org:12345/myapp');
Handlers
connection.onopen = function(){
console.log('Connection open!');
}
connection.onclose = function(){
console.log('Connection closed');
}
connection.onmessage = function(e){
var server_message = e.data;
console.log(server_message);
}
Documentation: http://www.developerfusion.com/article/143158/an-introduction-to-websockets/
Websockets will be the way to go once they are more universally implemented across the major browsers - I would guess a minimum of 5 years.
The last I heard Facebook chat uses comet and a whole bunch of servers. If you want something more lightweight I can think of two options.
Reduce the polling interval. This is strictly a UI issue - users may have a perfectly acceptable experience with intervals as long as a couple minutes. The only way to know for certain is through user testing, but polling every 5 seconds is probably overkill. No matter what you choose as the optimal interval, this does give you an quick way to scale if you are getting hammered - just crank up the interval until the servers stop melting.
Use HTTP validation caching. You can make the requests more lightweight if the server only returns a response body when the content has changed since the last request. You will have to build something custom using ETag or Last-Modified headers and a lightweight modification checking system on the server, but it might save you a few bytes.
By Default $.getScript() disables caching and you can use $.ajaxSetup and set caching to true. When testing if the script is actually cached with Firebug most of the time the script is coming back at 200 (Which means the script is a fresh copy) and one in maybe 20 or 30 times it will come back 304 (meaning it used a cached version). Why is it getting a new copy the vast majority of the time?
$.ajaxSetup({
cache: true
});
$.getScript( scriptFile );
The files that getScript retrieves have not been edited and the requests are a page change apart.
First lets clarify what is means that the jQuery disables the caching.
When jQuery disables the cache is means that is force the file to be load it again by the browser with some kind of trick, eg by adding one extra random number as parameter at the end of the url.
When jQuery have enable the cache, is not force anything and let the cache that you have set on the header of this file. Which means that if you do not have set on the header of the files parameters to keep it on browser cache, the browser will try to load it again by some methods.
So with enable the cache by jQuery you must also have been set the correct cache headers on your static files to be keep on browser cache, or else browser may try to load them again.
For files that browser see the created date on header, then is connect to the server asking the header again, is compare it and if is not have change then is not load it again, but is make one call to the server.
For files that you have set the a max age, and not ask the server till that date, then the browser is direct load it from the cache if he finds it.
To summarize:
The cache:true is let the browser decide for the cache of this file from the header you send.
The cache:false is force the file to be load again.
Some relative to cache questions:
caching JavaScript files
IIS7 Cache-Control
Tthe inside code
The getScript() is calling the jQuery.get() witch is a shorthand Ajax function of
$.ajax({
url: url,
data: data,
success: success,
dataType: dataType
});
So by calling the getScript() you make an ajax call, and the jQuery did not keep any kind of cache of your files if this is what you think at the first place.
Custom function to load the sripts
If you do not won to make a global cache:true, and you need only some files to be loaded with cache:true, you can make a custom function as:
function getScriptCcd(url, callback)
{
jQuery.ajax({
type: "GET",
url: url,
success: callback,
dataType: "script",
cache: true
});
};
This is not affected by the global cache parameter and is load the script files with out adding anything non-cache parameters at the end.
There is an error as of the date this question was posted where both Firefox and Chrome would state that a script is not being loaded from Cache when it indeed is. As of the date of this answer this issue still exists. The easiest way to test is to use console.log and send out a version number.
To cache a dynamically loaded script it it simply done by using the following code.
function onDemandScript ( url, callback ) {
callback = (typeof callback != 'undefined') ? callback : {};
$.ajax({
type: "GET",
url: url,
success: callback,
dataType: "script",
cache: true
});
}
For development you should comment out cache: true.
By default, $.getScript() sets the cache setting to false. This appends a timestamped query parameter to the request URL to ensure that the browser downloads the script each time it is requested.
jQuery doc site has a nice extension for not appending a timestamp to the request and bypass the cache:
jQuery.cachedScript = function( url, options ) {
// Allow user to set any option except for dataType, cache, and url
options = $.extend( options || {}, {
dataType: "script",
cache: true,
url: url
});
// Use $.ajax() since it is more flexible than $.getScript
// Return the jqXHR object so we can chain callbacks
return jQuery.ajax( options );
};
// Usage
$.cachedScript( "ajax/test.js" ).done(function( script, textStatus ) {
console.log( textStatus );
});
Source
There's a better option actually, you can turn ON caching for certain requests, for example:
$.ajaxPrefilter(function( options ) {
if ( options.type==='GET' && options.dataType ==='script' ) {
options.cache=true;
}
});
I know this is an old post, and the existing answer is the real answer, but touching on Iscariot's concern IT REALLY IS CACHING (at least kinda sorta). This is just a quirk of firefox. Maybe this will prove useful to others who are confused by this quirk.
I tested this concept with a REALLY LARGE javascript file that defines google map polygons for the Idaho DOT district boundaries based on arrays of tens of thousands of latlons (the uncompressed file size is 2,806,257, but I run it through a compression process). Using the following javascript
// Grab polys if not already loaded
if (typeof(defaults.data.polys) === 'undefined') {
/*$.getScript('/Scripts/ScriptMaster.php?file=Districts', function () {});*/
$.ajax({
type: "GET",
url: '/Scripts/ScriptMaster.php?file=Districts',
success: function() {
defaults.data.polys = getPolys();
data.polys = defaults.data.polys;
},
dataType: "script",
cache: true
});
}
and you can see the relevant php (you don't want the actual Districts.js file it would take too much space on this post, so here's ScriptMaster.php)
<?php
require_once('../settings.php');
if (!isset($_GET['file'])) die();
$file = $_GET['file'];
$doCache = $file == 'Districts';
header('Content-type: application/x-javascript');
if ($doCache) {
// This is a luxury for loading Districts.js into cache to improve speed
// It is at the top because firefox still checks the server for
// headers even when it's already cached
$expires = 7 * 60 * 60 * 24; // set cache control to expire in a week (this is not likely to change)
header('Cache-Control: max-age='.$expires.', must-revalidate');
header('Last-modified: Fri, 3 May 2013 10:12:37 GMT');
header('Expires: '.gmdate('D, d M Y H:i:s', time() + $expires).'GMT');
header('Pragma: public');
}
ob_start("compress");
require_once($file.".js");
ob_end_flush();
function compress($buffer) {
global $doCache;
if (DEV_MODE && !$doCache) return $buffer;
/* remove comments */
$buffer = preg_replace('/\/\/.+?$/m', '', preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer));
/* remove tabs, spaces, new lines, etc. */
$buffer = str_replace(array("\r\n", "\r", "\n", "\t", ' ', ' ', ' '), '', $buffer);
/* remove unnecessary spaces */
$buffer = str_replace(': ', ':', $buffer);
$buffer = str_replace(' :', ':', $buffer);
$buffer = str_replace(', ', ',', $buffer);
$buffer = str_replace(' ,', ',', $buffer);
$buffer = str_replace('; ', ';', $buffer);
$buffer = str_replace(' ;', ';', $buffer);
$buffer = str_replace('{ ', '{', $buffer);
$buffer = str_replace(' {', '{', $buffer);
$buffer = str_replace('} ', '}', $buffer);
$buffer = str_replace(' }', '}', $buffer);
if ($doCache) { header('Content-Length: '.strlen($buffer)); }
return $buffer;
}
?>
It's important to note that calling php's header functions BEFORE the script even executes the string you're going to print as unlike chrome and possibly (probably, I'm just too lazy to check) other browsers firefox appears to make a ping to server to check for headers before using cache. Maybe with more research you could determine if this pertains to elements in as equally as it does with ajax (probably not).
So I did five test runs showing the load times for this script with ajax as stated in firebug. Here are the results
#results loading the script after clearing cache (yes those are seconds, not ms)
200 OK 4.89s
200 OK 4.9s
200 OK 5.11s
200 OK 5.78s
200 OK 5.14s
#results loading the page with control+r
200 OK 101ms
200 OK 214ms
200 OK 24ms
200 OK 196ms
200 OK 99ms
200 OK 109ms
#results loading the page again by navigating (not refreshing)
200 OK 18ms
200 OK 222ms
200 OK 117ms
200 OK 204ms
200 OK 19ms
200 OK 20ms
As you can see, my localhost server to web client connection is not the most consistent and my laptop specs are a little shabby (single core processor and all, it's a few years old too) BUT THE POINT is there is a significant drop in load time after the cache is loaded.
[Also in case anyone's curious without the compression script (not like tabs, spaces or new lines are wasted, it just has to be readable still) takes somewhere between 7-8 seconds to load, but I'm not going to do that five times]
So never fear, it really is caching. For smaller scripts that only take ms's to load you may not notice the difference in firefox, honestly; simply because it checks for headers from the server. I know this because of the load time change from moving those header functions from the end of the script to the start. If you have those functions after php goes through the string it takes longer to load.
Hope this helps!
What do you perhaps are looking for is a getScriptOnce function, which basically, if it knows that the file was already loaded successfully, does not load again such file when such function is called.
I wrote such function. You can test with the Network tab in Firebug or Chrome dev tools. This just loads the same file once. You just need to copy to your files the getScriptOnce function and the global array ScriptArray
var getScriptOnce = (function(url, callback) {
var scriptArray = []; //array of urls
return function (url, callback) {
//the array doesn't have such url
if (scriptArray.indexOf(url) === -1){
if (typeof callback === 'function') {
return $.getScript(url, function(script, textStatus, jqXHR) {
scriptArray.push(url);
callback(script, textStatus, jqXHR);
});
} else {
return $.getScript(url, function(){
scriptArray.push(url);
});
}
}
//the file is already there, it does nothing
//to support as of jQuery 1.5 methods .done().fail()
else{
return {
done: function () {
return {
fail: function () {}
};
}
};
}
}
}());
/*#####################################################################*/
/*#####################################################################*/
//TEST - tries to load the same jQuery file twice
var jQueryURL = "https://code.jquery.com/jquery-3.2.1.js";
console.log("Tries to load #1");
getScriptOnce(jQueryURL, function(){
console.log("Loaded successfully #1")
});
//waits 2 seconds and tries to load again
window.setTimeout(function(){
console.log("Tries to load #2");
getScriptOnce(jQueryURL, function(){
console.log("Loaded successfully #2");
});
}, 2000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>