inform user during php calculation w/jquery - php

I'm writing code in PHP that analyzes user input.
I'm hoping to analyze it through a AJAX request using jquery.
I'd like to provide real-time feedback to the user while I'm preforming the calculations.
For example:
"Uploading your input", "Analyzing", "Preparing final result" and so forth.
How can I go abut doing this?

You will have to have a different back-end script do the processing than the one you are sending your request to. Your original ajax request can store the user input to be analyzed, and another process check for new data to work on regularly and start working when it finds some. That background process can then record its progress, e.g. using a file or a database.
The subsequent ajax requests will check that progress file or database entry and display the progress to the user.
Another (more complicated) solution would be to use Comet to push information on the status from the server to the browser. There is a comet plugin for JQuery in the works, as described in StackOverflow question 136012.

Assuming you have a service located at /service-status.php that checked the status of the job and returned a string you could do something like this in a interval.
var intervalId;
intervalId = setInterval( function() {
$.ajax({
type: "POST",
url: "/service-status.php",
data: "jobid=" + id,
success: function(msg){
if (msg === 'Finished') {
clearInterval( intervalId );
}
alert( "Status: " + msg );
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("He's dead Jim"):
clearInterval( intervalId );
}
})
}, 500);
This would poll your service every 500ms. It also assumes that you return 'Finished' when done. Adjust accordingly. I might put a counter in there too to clear the interval just in case so you don't DDOS your own server.

Related

Ajax Call Hangs Browser - I don't care about the response

How do I abort an Ajax call if I don't really care for the response as I don't want to hang the browser?
The situation is I have an ajax call that could trigger the server sending over a 1000 emails in some cases. 99% of the time it is only a few or tens of emails.
So with the 1000 email ajax call, the browser waits sometimes 5 minutes before it gets the success message, thus the user has to wait.
I have tried setting a timeout, but this still hangs. I'd like to wait about 20 seconds and then abort waiting for the response.
var request = jQuery.ajax({
type: "post",url: "admin-ajax.php",
data: {
action: 'send_email',
emailHTMLMessage: tinyMCE.activeEditor.getContent(),
_ajax_nonce: '<?php echo $nonce; ?>'
},
timeout: 20000, //Set your timeout value
success: function(html){ //so, if data is retrieved, store it in html
window.scrollTo(0,0);
sendResults(html);
},
error: function(jqXHR, textStatus, errorThrown) {
if(textStatus==="timeout") {
<... I'd redirect to another html page here....>
} else {
alert("Another error was returned"); //Handle other error type
}
}
}); //close jQuery.ajax
I have tried request.abort() but this kills it immediately and the server never gets the send_email message.
How can I quietly ignore the response after 20secs while the server carries on doing it's thing?
In this post there are afew ways to keet the script running after the http request ends:
Can a PHP script start another PHP script and exit?
So you can leave your email script running on the server.
If you want to know the status you could make your email script update to a mysql table how many emails are sent and check with an ajax request the count from the mysql table.
If you're sending 1000 emails, that call is going to contain some overhead no matter what you do. You are also going to have to wait until all the information is sent to the server before you want to allow the user to leave the page as well.
My suggestion would be to change the server code to respond as soon as the server gets their request. That way the client isn't waiting on the server to finish sending the entire batch, rather just waiting for their request to be received by the server.
Just post without using the success, timeout or error callbacks.
You might want to try creating a new get request for each email:
for(i = 0; i<1000; i++){
var request = $.ajax({
type: "post",
url: "admin-ajax.php",
data: {'i':'nada'}
});
};
In this case, I used a for loop, but you could also use an array of emails:
var emails = new Array(1000);
$.each(emails, function(){
var request = $.ajax({
type: "post",
url : "admin-ajax.php",
data: {'i':'nada'}
});
});

PHP jQuery Long Polling Chat Application

I've made a simple PHP jQuery Chat Application with Short Polling (AJAX Refresh). Like, every 2 - 3 seconds it asks for new messages. But, I read that Long Polling is a better approach for Chat applications. So, I went through some Long Polling scripts.
I made like this:
Javascript:
$("#submit").click(function(){
$.ajax({
url: 'chat-handler.php',
dataType: 'json',
data: {action : 'read', message : 'message'}
});
});
var getNewMessage = function() {
$.ajax({
url: 'chat-handler.php',
dataType: 'json',
data: {action : 'read', message : 'message'},
function(data){
alert(data);
}
});
getNewMessage();
}
$(document).ready(getNewMessage);
PHP
<?php
$time = time();
while ((time() - $time) < 25) {
$data = $db->getNewMessage ();
if (!empty ($data)) {
echo json_encode ($data);
break;
}
usleep(1000000); // 1 Second
}
?>
The problem is, once getNewMessage() starts, it executes unless it gets some response (from chat-handler.php). It executes recursively. But if someone wants to send a message in between, then actually that function ($("#submit").click()) never executes as getNewMessage() is still executing. So is there any workaround?
I strongly recommend that you read up on two things: the idea behind long polling, and jQuery callbacks. I'll quickly go into both, but only in as much detail as this box allows me to.
Long polling
The idea behind long polling is to have the webserver artificially "slow down" when returning the request so that it waits until an event has come up, and then immediately gives the information, and closes the connection. This means that your server will be sitting idle for a while (well, not idle, but you know what I mean), until it finally gets the info that a message went through, sends that back to the client, and proceeds to the next one.
On the JS client side, the effect is that the Ajax callback (this is the important bit) is delayed.
jQuery .ajax()
$.ajax() returns immediately. This is not good. You have two choices to remedy this:
bind your recursion call in the success and error callback functions (this is important. the error function might very well come up due to a timeout)
(see below):
Use This:
var x = $.ajax({blah});
$.when(x).done(function(a) { recursiveCallHere(); });
Both amount to the same thing in the end. You're triggering your recursion on callback and not on initiation.
P.S: what's wrong with sleep(1)?
In long polling new request should be initiated when you have received the data from the previous one. Otherwise you will have infinite recursion in browser freezing.
var getNewMessage = function() {
$.ajax({
url: 'chat-handler.php',
dataType: 'json',
data: {action : 'read', message : 'message'},
success: function(data) {
alert(data);
getNewMessage(); // <-- should be here
}
});
}

javascript autoupdate when a sql record is changed (or equals some specific value)

Is it possible for javascript to update automatically if a mySQL field is modified? I'm assuming this basically translates to some kind of a constant query of a specific SQL record.
For an example, lets suppose I'm making a simple /multiplayer/ tic-tac-toe using PHP and jquery with a mySQL background.
I want the tic-tac-toe page to be powered by jquery so that the user does not have to do a page refresh.
Two users get hooked up and the game begins. User 2 waits while user 1 thinks about where to put an X. When User 1 clicks a square to include an X, I'd like for user 2 to have their screen automatically changed to reflect - without having to press any buttons to check for updates.
You could poll the server every X seconds (say 10 seconds) via AJAX to check if it's changed. Theres no (easy) way of pushing data to the client side.
Example code:
function checkStatus() {
setTimeout('checkStatus()',10000);
$.ajax({
url: "checkStatus.php",
    success: function(data){
      //Code to handle change goes here
    }
  });
}
setTimeout('checkStatus()',10000);
You have two main solutions, polling or websockets(which isn't fully supported in all browsers btw), both involve communicate with the backend. I'm not going to cover websockets, however it is an up and coming technology that keeps an open connections from the frontend to the backend. Another option is using something like Comet, which allows you to keep an HTTP connection open for a long time.
The other solution you have is polling, in which you make an ajax request every x seconds to "poll" for changes.
This could be done using Ajax (use JQuery Ajax). It could refresh every couple of seconds to update the page with the latest content from the database. This approach is fine on a small scale with a low a number users but is very draining on your server's resources as it is constantly sending and receiving data even if new data is not available.
A better option may be to use node.js and socket.io to support large scale real time processes.
Yes - one way is to use a long-polling comet. Essentially, this works by making an asynchronous (typically with AJAX) request from the server and waiting for the response. The wait can be for an hour, say. When it receives a response, it 'completes' the request and then sends another request in the same way.
There are lots of other ways though - check out 'push technology'.
I'd been trying to use setTimeout but had no success. I used setInterval and it seems to work like a charm.
Code follows:
function waitForMsg(){
$.ajax({
url: "tictac_code1.php",
type: 'POST',
data: 'longpoll=1',
async: true, /* If set to non-async, browser shows page as "Loading.."*/
cache: false,
timeout:10000, /* Timeout in ms */
success: function(data){ /* called when request to barge.php completes */
$('#loggedinnames').empty();
$('#loggedinnames').append(data);
setInterval(waitForMsg, 10000);
//setTimeout(
// 'waitForMsg()', /* Request next message */
// 1000 /* ..after 1 seconds */
//);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
//alert("error in waitformsg.");
addmsg("error", textStatus + " (" + errorThrown + ")");
setInterval(waitForMsg, 10000);
//setTimeout(
// 'waitForMsg()', /* Try again after.. */
// "15000"); /* milliseconds (15seconds) */
}
});
};
$(document).ready(function(){
waitForMsg(); /* Start the inital request */
});

Need explanation of comet program

I am new to Comet programming. I searched through and write the code like this
<script type="text/javascript" charset="utf-8">
function waitForMsg(){
$.ajax({
type: "GET",
url: "getMessage.php",
async: true,
cache: false,
timeout:50000,
success: function(data){
$('#messages).append(data);
setTimeout(
'waitForMsg()',
1000
);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
addmsg("error", textStatus + " (" + errorThrown + ")");
setTimeout(
'waitForMsg()',
"15000");
},
});
};
$(document).ready(function(){
waitForMsg();
});
</script>
I am getting update from getMessage.php when ever i am passing a message to getMessage.php
But my doubt is i used
setTimeout('waitForMsg()',1000);
What this means. If we are calling waitForMsg() for every 1 sec then what is the difference between Ajax and Comet programming.
Regarding your example, the difference between Ajax and Comet depends on how getMessage.php responds to the request from the client.
Using Ajax, getMessage.php would return immediately even if there are no new messages to return. The client would then wait the specified interval and then send another request, again either receiving a new message or nothing at all. End result is that the quickest the client will ever update with a new message is the specified interval.
Using Comet, on the other hand, getMessage.php would not return until it has something to return. Meaning on initial request from the client it would check for new messages, if none are available it would sleep for a certain amount of time and check again. This process would continue until a new message is available or a timeout occurs, at which point the client would send another request to the server and the process starts over. End result in this case is that the client would appear to update instantaneously.
There are multiple kinds of COMET. You're using AJAX polling, but there are other techniques, like forever-frame, that do not involve polling.
Forever-frame uses a hidden infinitely long iframe that the server pushes script tags to as needed.
Also note that some uses of AJAX polling (e.g. as explained by the Wikipedia) do not include a setTimeout, since they immediately start a new AJAX request in the success handler.
Also (with the AJAX polling example), you can just use:
setTimeout(waitForMsg, 1000);
There is no need for a string.

How to delay ajax query?

I read a lot of questions, but they doesn't working in my case.
My situation is: my ajax query to database to insert infromation. But in my web-application user can click on buttons very quick so previous ajax query is not finished, and there is where bugs are appear.
All i need to do is a delay between queries, so future queries will do only after previous is done.
Here is a code:
$('#save').click(function(){
var user_input=$('#user').val();
var section=$('#section').val();
$('#loading_info').append('<p><img src="Images/loading.gif" alt="loading" id="loading"/></p>');
$.ajax({
url: 'submit_db.php',
type: 'POST',
data: 'section='+section+'&user_input='+user_input,
success: function(result){
$('#response').remove();
$('#loading_info').append('<p id="response">' + result + '</p>');
$('#loading').fadeOut(500, function(){
$(this).remove();
});
}
});
return false;
});
What i tested and not working: insert timeout:3000 into ajax - 1 query is ok, but after this, the whole application freezes; set timeout using ajaxSetup() - the same situation. Tested setInterval function and put ajax query to it - but after it there were no ajax, application opened an implementing php file and freezes.
This not working:
$('#save').click(function(){
var t=setTimeout(function(){
var user_input=$('#user').val();
var section=$('#section').val();
$('#loading_info').append('<p><img src="Images/loading.gif" alt="loading" id="loading"/></p>');
$.ajax({
url: 'submit_db.php',
type: 'POST',
data: 'section='+section+'&user_input='+user_input,
success: function(result){
$('#response').remove();
$('#loading_info').append('<p id="response">' + result + '</p>');
$('#loading').fadeOut(500, function(){
$(this).remove();
});
}
});
return false;
},3000);
});
And this is not working too:
$('#save').click(function(){
var user_input=$('#user').val();
var section=$('#section').val();
$('#loading_info').append('<p><img src="Images/loading.gif" alt="loading" id="loading"/></p>');
$.ajax({
url: 'submit_db.php',
type: 'POST',
timeout: 3000,
data: 'section='+section+'&user_input='+user_input,
success: function(result){
$('#response').remove();
$('#loading_info').append('<p id="response">' + result + '</p>');
$('#loading').fadeOut(500, function(){
$(this).remove();
});
}
});
return false;
});
And finally this is not work too:
$.ajaxSetup({
timeout:3000,
});
Thanks in advance
What I suggest is to create a boolean and disable any button.
Create a boolean called "buttonPressed", this is set to false. When a submit is made, you check in your code if "buttonPressed" is set to false. If this isn't set to false, skit the AJAX request, otherwise set the buttonPressed to true and do the AJAX request. When the request is done, set the buttonPressed back to false and a new buttonpress will be allowed.
The problem is propably in that: user clicks 3 times in second, and afeter 3 seconds of timeouts, three quersies and sended in one second.
Use setTimeout, but clear this timeout everytime user clicks, so every time user clicks, timer is reseted, and you don't have to worry about query "queue".
Other solution is to detect does timer working, and ignore or queue user click (queue by creating new timet with value of 3000 + rest time of the actual timer
Paul Peelen's answer is probably the best one for you, but another safe solution would be to queue your requests. It will allow your code to execute asynchronously but still sequentially and even (potentially) allows you to kill duplicate requests before they even leave the machine. The way I've done this is something like this:
Create an array to hold your requests.
When the user's action causes a request, throw it into the end of the queue.
Immediately call a queue processor. If a previous requests hasn't resulted in a response yet, do nothing -- just leave it in the queue. Otherwise, remove the first item from the queue and process it. At this point, you could also look through the other queued requests and remove duplicates, or push high-priority requests to the top of the queue.
When the response is received, send it to wherever it needs to go and tell the queue processor to process the next request.
It's actually pretty simple to build, and I'm sure there are better variations out there. If server stability is a possible issue, you should build in some sort of process to kill dead requests (zombies).
Use a sentinel variable so that only one request can happen at a time. If it makes sense for the user to be able to have more than one request going then implement a queue for the requests, where the call to process the next element in the queue happens after the previous request has been handled.

Categories