Page 5

Bundled AJAX

I hope you’ve seen how easy it can be to send multiple AJAX requests and to the server in only one request. This is a great way to (1) maintains the order of your AJAX requests and responses, (2) provides less load on your server, and (3) preserves a responsive UI. If you missed the intro, check out this post for more a complete discussion of this tutorial’s motivation, or browse back to page 1.

The Source Code

Click the links below to view the full source code for the tutorial, or download it to use in your own projects.

Download It HereBundled Synchronous AJAX

Conclusion

Thanks for reading through my bundled AJAX tutorial – I certainly hope you found it helpful! You can also browse the tutorials page for completely different tutorials, or check out some of my other projects. Or of course, browse back in time to the previous pages in this tutorial:

Close
jQuery.extend({

	/**
	 * keep track of multiple queues
	 */
	bAjaxQs : { },

	/**
	 * define the functionality
	 * for a bundled AJAX Queue
	 */
	bAjaxQ : function(q_options){

		var inQ = new Array();
		var sending = false;
		var sendingQ = new Array();
		var opt_success = q_options.success;

		/**
		 * the bundled AJAX request came back successfully
		 * so notify each request in the queue of it's
		 * specific response, in the order the reqest was sent
		 */
		function success(data){
			sending = false;
			$.each(sendingQ, function(i){
				if(sendingQ[i].success) sendingQ[i].success(data[i]);
			});
			if(opt_success){
				opt_success(data, inQ.length);
			}
			sendQ();
		}

		/**
		 * simple function to escape \ ' and " with a \
		 */
		function addslashes(str){
			return (str+'').replace(/([\\"'])/g, "\\$1");
		}

		/**
		 * simple function to serialize an object
		 * to a json string
		 */
		function serialize(obj){
			var out = "";
			$.each(obj, function(i, val){
				out = out + "\"" + i + "\" : \"" + addslashes(val) + "\",";
			});
			if(out.length) out = out.substr(0, out.length - 1);
			return "{" + out + "}";
		}

		/**
		 * if our queue has items ready to send,
		 * then bundle them up into a single request
		 * and send it
		 */
		function sendQ(){
			if(inQ.length){
				sending = true;
				sendingQ = inQ;
				inQ = new Array();

				var data = "[";

				$.each(sendingQ, function(i){
					if(data.length > 1) data += ",";
					data += serialize(sendingQ[i].data);
				});
				data += "]";

				$.ajax($.extend(q_options,{
					data : { data : data },
					success : success
				}));
			}
		}

		/**
		 * add the input request to the queue
		 * and send the queue if we can
		 */
		this.addToQ = function(options){
			inQ.push(options);
			if(!sending) sendQ();
		}
	},

	/**
	 * Send a bundled AJAX request
	 */
	bAjax: function(q_options, options){
		if(!this.bAjaxQs[q_options.url]){
			this.bAjaxQs[q_options.url] = new this.bAjaxQ(q_options);
		}
		this.bAjaxQs[q_options.url].addToQ(options);
	}

});
Close
<?
// include MYSQL config
include "config.php";

// connect to DB
$mysql = mysql_connect(DB_HOST, DB_USER , DB_PASSWORD);
mysql_select_db(DB_NAME, $mysql);

// run a query on mysql,
// and throw an exception if there's
// a problem
function query($sql){
	global $mysql;
	$result = mysql_query($sql, $mysql);
	if(mysql_error($mysql)){
		throw new Exception("mysql error");
	}
	return $result;
}

// get the current value
// of The Number
function getCount(){
	// get the current number result
	$sql = "SELECT c FROM counter";
	$result = query($sql);

	$count = 0;
	while($row = mysql_fetch_array($result)){
		$count = (int) $row["c"];
	}
	return $count;
}

//
// get the JSON input and parse
$json_in = "";
if(get_magic_quotes_gpc()){
	$json_in = stripslashes($_REQUEST["data"]);
}else{
	$json_in = $_REQUEST["data"];
}
$data = json_decode($json_in);

// prep the response
$ret = array();

//
// track how many "up" and "down"
// that the user sent in, if any
// (it could just be a "refresh"
//  command)
$the_number = getCount();
$delta = 0;
for($i=0;$i<count($data);$i++){
	if(isset($data[$i]->func)){
		if($data[$i]->func == "down") $delta -= 1;
		else if($data[$i]->func == "up") $delta += 1;
		$ret[] = $the_number + $delta;
	}
}
// update the The Number if we need to
if($delta != 0){
	$sql = "UPDATE counter SET c = c + " . $delta;
	query($sql);
}
// close DB connection to clean up
mysql_close($mysql);

// sleep for a bit, so the user can
// better see how combined AJAX works
usleep(500000);

// send the result back
echo json_encode($ret);

?>
Close
<html>
	<head>
		<script src="jquery.js" type="text/javascript"></script>
		<script src="bajax.js" type="text/javascript"></script>
		<script type="text/javascript">

			/**
			 * keep track of how many
			 * requests are in the queue
			 * waiting to be sent
			 */
			var qcount = 0;

			/**
			 * set up default options for
			 * the AJAX calls
			 */
			var bAjaxOptions = {
				url : "ajax.php",
				type : "POST",
				dataType : "json",
				success : function(data, q_len){
					qcount = q_len;
					$("#queue").text("Requests in Queue: " + (qcount));
					if(q_len == 0){
						refresh();
					}
				}
			};

			/**
			 * send a no-op command to the server
			 * to retrive the latest count
			 */
			function refresh(){
				$.bAjax(bAjaxOptions, {
					data : { func : "refresh" },
					success : function(data){
						$("#theNumber").text("The Number: " + data);
					}
				});
			}

			/**
			 * Increase the counter
			 */
			function goUp(){
				$.bAjax(bAjaxOptions, {
					data : { func : "up" },
					success : function(data){
						$("#theNumber").text("The Number: " + data);
					}
				});
				$("#queue").text("Requests in Queue: " + (++qcount));
			}

			/**
			 * Decrease the counter
			 */
			function goDown(){
				$.bAjax(bAjaxOptions, {
					data : { func : "down" },
					success : function(data){
						$("#theNumber").text("The Number: " + data);
					}
				});
				$("#queue").text("Requests in Queue: " + (++qcount));
			}

			/**
			 * listen for clicks on up and down links
			 */
			$(function(){
				$("#up").click( goUp );
				$("#down").click( goDown );
			});

			/**
			 * begin the AJAX loop
			 */
			refresh();
		</script>
	</head>
	<body>
		<h3 id="theNumber">
			The Number: Loading...
		</h3>
		<h3 id="queue">
			Requests in Queue: 0
		</h3>
		<p>
			<a id='up' href='javascript:;'>Increase "The Number"</a>
		</p>
		<p>
			<a id='down' href='javascript:;'>Decrease "The Number"</a>
		</p>
		<div id="console">
			<br><br>
			Clicking either link will fire off an AJAX request to increase or decrease a global counter.
			The counter is shared by all users, and will update in real time as its changed by anyone.
			<br><br>
			The server is set up with a 1/2 second lag, and your requests are queued until the server
			has finished processing your last request.
		</div>
	</body>
</html>
Close
<?

// ** MySQL settings ** //
define('DB_NAME', 'yourDB');    // The name of the database
define('DB_USER', 'yourUser');     // Your MySQL username
define('DB_PASSWORD', 'yourPassword'); // ...and password
define('DB_HOST', 'yourHost');    // 99% chance you won't need to change this value

?>
Close
--
-- Set up a simple table to track The Number
--

CREATE TABLE `counter` (
  `c` bigint(20) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

INSERT INTO `counter` VALUES(0);

Post to Twitter Tweet This

1 Comment

1 response so far ↓

  • 1 Steven Black // Nov 20, 2008 at 12:30 am

    Well, excuse me! This is brilliant. Thanks for sharing it.

Leave a Comment or