ajax firing multiple times after database becomes unlocked - php

I'm having a problem with an ajax call.
I have some code set up to run a function every 2 seconds which looks to see if the content has been updated or not with WordPress ajax, does some work with php, then updates a database:
window.setInterval( "updateContent()", 2000 );
function updateContent(){
if($('#needcontent').hasClass('yes')){
CONTENT.updateContent( 'monitor' , ids );
}
}
$(function() {
CONTENT= {
updateContent: function(callback, data){
data = {
action: 'myplugin_do_ajax',
callback: callback,
data: data
};
$.post(ajaxurl, data, function(response){
switch(data.callback){
case 'monitor' :
data_returned = eval("(" + response + ")");
if(data_returned.completed == 'true'){
//Adjust the DOM because there was a content update, and remove the class "yes" from #needcontent to stop the check until next time
}
else{
//Do nothing because no content was found, let the Interval run again
}
break;
}
}
}
}
The problem I'm finding is that sometimes the content is quite large, and ends up locking the table while php updates the database. The ajax call runs once, runs into a database lock, and doens't return anything until the database is unlocked again. The database could be locked for a 10 second period, resulting in 1 run and 4 not-run calls.
UPDATE:
It's not the database locking, it's the php function taking longer than 2 seconds to return, causing the Interval to loop again and again without a response.
What's happening is those 4 not-run ajax calls then begin to fire one right after the other like they are trying to catch up or something.
I've tried increasing the Interval time to 10 seconds, but that doesn't solve the problem because if the database is locked for 11 seconds it'll still fire twice.
I've tried using global variables in Javascript (yuck) to stop the Interval from calling the function, but that doesn't seem to work either.
UPDATE 2:
I answered my own question below to what worked for me.

try this:
window.updateCheck= window.setInterval( "updateContent()", 2000 );
function updateContent(){
if($('#needcontent').hasClass('yes')){
CONTENT.updateContent( 'monitor' , ids );
clearInterval(window.updateCheck);
}
}
$(function() {
CONTENT= {
updateContent: function(callback, data){
data = {
action: 'myplugin_do_ajax',
callback: callback,
data: data
};
if(window.ajaxCall) window.ajaxCall.abort();
window.ajaxCall= $.post(ajaxurl, data, function(response){
window.updateCheck= window.setInterval( "updateContent()", 2000 );
switch(data.callback){
case 'monitor' :
data_returned = eval("(" + response + ")");
if(data_returned.completed == 'true'){
//Adjust the DOM because there was a content update, and remove the class "yes" from #needcontent to stop the check until next time
}
else{
//Do nothing because no content was found, let the Interval run again
}
break;
}
}
}
}
what we did here was to put the interval in a global variable, and also the ajax call ($.post() call actually), then when the conditions of updating is checked, we stop the interval, kill all the other active or queued request and send the ajax request to the server.
while the request is being sent to the server the update checks are stopped, then as soon as the server responds to the request we start the update check again!

charlietfl's comment on my OP got me thinking about the difference between setInterval and setTimeout, and I realized that:
a) setInterval would continuously run, regardless if a result is returned or not. In my case, using ajax, the function was being call asynchronously so the setInterval wouldn't care if a result was returned.
b) If I changed the code to use setTimeout, I could control the outcome more.
This is what I did.
Firstly, remove the setInterval function completely, it's not needed.
Then I changed my switch case to this:
case 'monitor' :
var monitor = false;
data_returned = eval("(" + response + ")");
if(data_returned.completed == 'true'){
//Adjust the DOM because there was a content update, and remove the class "yes" from #needcontent to stop the check until next time
}
else{
//Run the monitor after a 2 second timeout.
var ids = j('.contentDiv').attr('id');
window.setTimeout(CONTENT.updateContent( 'monitor' , ids ) , 2000);
}
break;

Related

Ajax/PHP long-polling results in 503 error

I'm playing around with AJAX long-polling and trying to read/update a simple counter (number) value in an MySQL cell by clicking on a button.
The PHP creates an infinite while loop and is checking if the value in the according cell has been modified (MySQL "current_timestamp", UNIX). If it has and the current_timestamp value is bigger then the timestamp the AJAX call was made, it's breaking the loop and sending the updated value and the updated current_timestamp to the client. The AJAX processes the data.
The Problem: It works but after a while I get a 503 error. I guess it's obviously the while loop or other open connections through multiple windows in other browsers (for testing).
PHP-File text.php:
// Connect to database
$con = mysql_connect('XX', 'XX', 'XX');
if (!$con)
{
die('Error' . mysql_error());
}
mysql_select_db('X', $con);
// Get data
$query = mysqli_query("SELECT counter_value, last_modified FROM content WHERE X = 'X' ORDER BY X DESC");
// Start infinite loop
set_time_limit(0);
while (true)
{
// The timestamp of the last ajax call = the last modified timestamp
$last_ajax_call = $_GET['timestamp'];
clearstatcache();
// Get the value of the counter and the last modified timestamp
while($row = mysql_fetch_array($query))
{
$counter_value = $row['counter_value'];
$last_modified= strtotime($row['last_modified']);
}
// If the time of the last modified timestamp is bigger/later than the last ajax call
if ($last_modified > $last_ajax_call)
{
$result = array(
'counter_value' => $counter_value,
'timestamp' => $last_modified
);
$json = json_encode($result);
echo $json;
break;
// If not, try again in 3 seconds
} else
{
sleep(3);
continue;
}
}
// Close database
mysql_close($con);
AJAX Part in js-File:
function getContent()
{
// get timestamp of last modified stored in attribute. The initial/first timestamp attribute is set beforehand.
var timestamp = $('#timestamp').attr('data-timestamp');
$.ajax(
{
type: 'GET',
url: 'test.php',
async: true,
cache: false,
data: {timestamp:timestamp},
success: function(data){
var obj = jQuery.parseJSON(data);
$("#counter").text(obj.counter_value);
$("#timestamp").attr("data-timestamp", obj.timestamp);
getContent();
}
}
);
}
getContent();
So the result is a 503 error which goes away after ca. 10 Minutes and it's working again.
(Any typos/formatting might be the result of cleaning up the code.)
I just started learning PHP and JS, so there might be a few newbie mistakes or weird lines in there, please be nice. Any advice on optimising the code is very appreciated!
It dies because PHP doesn't work the way you think it does.
You have intentionally put an infinite loop into your php in the assumption it will make your code keep looping around and rechecking the next GET request on each loop.
The reality is that the code is executed once for each request, and until execution of the code completes the server doesn't respond.
AJAX long polling requires no special handling in php, it's just an AJAX request in a loop. You might want to include a slight delay in your AJAX code otherwise your server will be hammered with requests.
To be honest this isn't what long polling is for, the idea of it is to update pages without any user interaction to display unread message notifications etc.
If you want to monitor user events like button clicks then bind your AJAX function to the clicking of the button.

How do I insert a chunk of code every time my while loops fetches some data from my database

I have a table in my database. I use a while loop to traverse them. and make a HTML div with that fetched data. I used LIMIT 10 because entries in posts will keep changing as users will keep inserting posts into the table
$get_ids=mysql_query("SELECT * FROM posts ORDER BY id LIMIT 10");
while($row = mysql_fetch_array($get_ids)){
$sm=$row['message'];
echo "<div>".$sm"</div>";
}
What i want to know is how do i use jquery to make this script insert these 10 divs into my DOM every 1 second or so. Help please URGENT!!!!
Try to google for some jquery & php webservice examples. Basically you should do something like this:
//Javascript function which fetches the single data as J.D.Smith suggested
function getHtml()
{
$.get({
'url': 'Address of your php webservice',
'success': function(data) {
$("#content").html($("#content").html() + data); //Append html to your page
}
});
}
//Call the function every 10 sec, place it in $(document).ready() or anything else you use
window.setTimeout(function () {
getHtml();
}, 10000);
This code is more to be illustrative sample than working code
You'd put that code in a separate file (for example: divfill.php) and then use something like this
$.get({
'url': 'divfill.php',
'success': function(data) {
$("#content").html($("#content").html() + data);
}
});
In my case, I have added the following method in my js file,
//call the target function after 250 ms
function async(targetFn, callback) {
setTimeout(function () {
targetFn();
callback();
}, 250);
}
And, I call this function as shown below,
async(BindValuesInLookup, function () {
BuildGrid()
GetInfo();
});
BindValuesInLookup is the target function. It gets fired after 250ms. Once it is done, the callback functons will be executed. So you can use this functionality in the loop and increase the timeout to 1000 (1 sec).
Thanks,
Vim

AJAX/PHP Auto Display Updated Value

I have a simple question, I'm sure. I just don't know what I should be searching for on google. It'd probably be easier for me to explain:
For example I have a mysql field with the value 'Yes'
How do I with AJAX/PHP keeping querying the field for when the value changes to 'No'?
Could someone explain, in simple terms please
There are two function that will help.
setTimeout ( expression, timeout );
setInterval ( expression, interval );
Where expression is a function and timeout and interval are integers in milliseconds. setTimeout runs the timer once and runs the expression once whereas setInterval will run the expression every time the interval passes.
So in your case it would work something like this:
setInterval(function() {
//call $.ajax here
$.ajax({
url : URL,
data : passData,
dataType : 'json', //or html or xml
beforeSend : function()
{
//this will execute before request is send
},
success : function(response)
{
//check for response if( response ) { } else { }
}
});
}, 5000); //5 seconds
Now the backend php file.
<?php
$passedVar = $_REQUEST['passedData']; //get data that were passed in ajax call
//database connection
//query to check for status
if(query return true)
{
echo json_encode(true);
exit;
}
else
{
echo json_encode(false);
exit;
}
first create a JavaScript function which will execute ajax call then put that function on setInterval()
function ajaxcall(){
// you ajax call;
}
setInterval(ajaxcall, 10000);// change time by replacing 10000(time is in millisecond)
Here ajaxcall will be called in every 10 second.You can do anything inside ajaxcall function I mean checking your database value by ajax.

Refresh div, but only if there is new content from php file

Background Info
I'm fiddling around with some PHP and AJAX at the moment, to try and get the code working for an auto refreshing div (every 10 seconds), that contains comments.
Here is javascript code I am using to refresh the div..
<script type="text/javascript">// <![CDATA[
$(document).ready(function() {
$.ajaxSetup({ cache: false });
setInterval(function() {
$('#content_main').load('/feed_main.php');
}, 5000);
});
// ]]></script>
The code that will populate the div called "content_main", which is in feed_main.php, essentially accesses the database and echo's out the latest comments ...
Question
Is it possible, to only load the div "content_main" if the data inside of it, hasn't changed since the last time it was loaded?
My logic
Because I'm relatively new to javascript and AJAX I don't quite know how to do this, but my logic is:
For the first time it is run..
load data from feed_main.php file
Create a unique value (perhaps a hash value? ) to identify say 3 unique comments
Every other time it is run...
load the data from feed_main.php file
create a NEW unique value
check this value with the previous one
if they're the same, don't refresh the div, just leave things as they are, but if they're different then refresh..
The reason why I want to do this is because the comments usually have pictures attached, and it is quite annoying to see the image reload every time.
Any help with this would be greatly appreciated.
I've faced similar problem not too long ago, i assume that you using mysql or something for your comments storage serverside ?
I solved my problem by first adding timestamp integer column to my mysql table, then when i added a new row, i'd just simply use time() to save the current time.
mysql row insert example:
$query = "INSERT INTO comments (name, text, timestamp) VALUES ('". $name ."', '". $text ."',". time() .");";
step two would be to json_encode the data you sending from serverside:
$output = array();
if ($html && $html !== '') { // do we have any script output ?
$output['payload'] = $html; // your current script output would go in this variable
}
$output['time'] = time(); // so we know when did we last check for payload update
$json = json_encode($output, ((int)JSON_NUMERIC_CHECK)); // jsonify the array
echo $json; // send it to the client
So, now instead of pure html, your serverside script returns something like this:
{
"payload":"<div class=\"name\">Derpin<\/div><div class=\"msg\">Foo Bar!<\/div>",
"time":1354167493
}
You can grab the data in javascript simply enough:
<script type="text/javascript"> // <![CDATA[
var lastcheck;
var content_main = $('#content_main');
pollTimer = setInterval(function() {
updateJson();
}, 10000);
function updateJson() {
var request = '/feed_main.php?timestamp='+ (lastcheck ? lastcheck : 0);
$.ajax({
url: request,
dataType: 'json',
async: false,
cache: false,
success: function(result) {
if (result.payload) { // new data
lastcheck = result.time; // update stored timestamp
content_main.html(result.payload + content_main.html()); // update html element
} else { // no new data, update only timestamp
lastcheck = result.time;
}
}
});
}
// ]]> </script>
that pretty much takes care of communication between server and client, now you just query your database something like this:
$timestamp = 0;
$where = '';
if (isset($_GET['timestamp'])) {
$timestamp = your_arg_sanitizer($_GET['timestamp']);
}
if ($timestamp) {
$where = ' WHERE timestamp >= '.$timestamp;
}
$query = 'SELECT * FROM comments'. $where .' ORDER BY timestamp DESC;';
The timestamps get passed back and forth, client always sending the timestamp returned by the server in previous query.
Your server only sends comments that were submitted since you checked last time, and you can prepend them to the end of the html like i did. (warning: i have not added any kind of sanity control to that, your comments could get extremely long)
Since you poll for new data every 10 seconds you might want to consider sending pure data across the ajax call to save substantial chunk bandwidth (json string with just timestamp in it, is only around 20 bytes).
You can then use javascript to generate the html, it also has the advantage of offloading lot of the work from your server to the client :). You will also get much finer control over how many comments you want to display at once.
I've made some fairly large assumptions, you will have to modify the code to suit your needs. If you use my code, and your cat|computer|house happens to explode, you get to keep all the pieces :)
How about this:
<script type="text/javascript">
// <![CDATA[
$(function () {
function reload (elem, interval) {
var $elem = $(elem);
// grab the original html
var $original = $elem.html();
$.ajax({
cache : false,
url : '/feed_main.php',
type : 'get',
success : function (data) {
// compare the result to the original
if ($original == data) {
// just start the timer if the data is the same
setTimeout(function () {
reload(elem, interval)
}, interval);
return;
}
// or update the html with new data
$elem.html(data);
// and start the timer
setTimeout(function () {
reload(elem, interval)
}, interval);
}
});
}
// call it the first time
reload('#content_main', 10000);
});
// ]]>
</script>
This is just an idea to get you going it doesn't deal with errors or timeouts.
Best And Easy Code
setInterval(function()
{
$.ajax({
type:"post",
url:"uourpage.php",
datatype:"html",
success:function(data)
{
$("#div").html(data);
}
});
}, 5000);//time in milliseconds

Looping though JSON data and displaying it in a DIV

I have a page with some checkboxes and a submit button. I use AJAX to post the checkbox values to a PHP script, calc.php, run some calculations with the data and assign the result to a PHP session variable. I have another PHP script, json.php, that takes that session data and encodes it as JSON for the jquery to display in the div. My problem is I allow the user to set the amount of data sets they are going to submit, subnumber, and my display loop gets out of sync when the user changes the number of sets.
For example, if they start with 3 data sets, they submit them one by one by pressing #button. After the last set, if (count == max) runs and. Now they can do another calculation and change the number of data sets if they wish. If they change it to say 2, output goes to four instead of reseting to 1 and emptying #log.
$("#button").click(function() {
$.ajax({
type: "POST",
url: "calc.php",
data: $("form#checkboxes").serialize(),
success: function(data) {
if(document.getElementById('calc').checked) {
var max = checkboxes.subnumber.value;
var stop = Number(max) + 1;
count++;
output++;
$.getJSON('json.php', function(data) {
$.each(data, function(key, val) {
$('#log').append(output);
$('#log').append(val.result);
$('#log').append("</br>");
})
})
if (count == max){
count = 0;
$("#results").load('results.php')
}
if(output == stop) {
$("#log").empty();
output = 1;
}
}
}
})
}
I know it's something simple, but I have been trying to fix it for two hours now and can't figure out the problem. Everything else works perfectly, it's just the output counter that isn't done correctly.
You're running asynchronous calls into your JSON. If users are doing things so quickly that the calls are coming back out of order, the issue lies in there.
You've got two options:
Run all of your JSON synchronously (use async:false in your JSON calls)
Utilize a counter and only process events that are coming back on the current index.
Psuedo Code for #2:
var pCounter = 0;
function doSomeAjax()
{
pCounter++;
$.ajax('url',{
data:{count:pCounter}
success:function(data)
{
// your json should return the current counter index
if (data.counter != pCounter) return;
// execute normally.
}
});
}

Categories