<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:series="http://unfoldingneurons.com/"
	>

<channel>
	<title>Ovalpixels Blog about Web-Building &#187; controller</title>
	<atom:link href="http://www.ovalpixels.com/blog/tag/controller/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ovalpixels.com/blog</link>
	<description>Tips &#38; Tricks on Web Design and Development</description>
	<lastBuildDate>Fri, 28 Jan 2011 09:17:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Highly responsive ajax applications without excess requests and bandwidth waste?</title>
		<link>http://www.ovalpixels.com/blog/2008/11/15/highly-responsive-ajax-applications-without-excess-bandwidth-waste/</link>
		<comments>http://www.ovalpixels.com/blog/2008/11/15/highly-responsive-ajax-applications-without-excess-bandwidth-waste/#comments</comments>
		<pubDate>Sat, 15 Nov 2008 00:42:17 +0000</pubDate>
		<dc:creator>georgi</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[controller]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[Pagebaker]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[real time]]></category>
		<category><![CDATA[responsive ajax applications]]></category>

		<guid isPermaLink="false">http://www.ovalpixels.com/blog/?p=3</guid>
		<description><![CDATA[Ajax is not as powerful as one would imagine If you have ever tried to develop a robust ajax application, you have probably reached a point where you want the client to be notified about a change on the server in &#8220;real time&#8221;. The most simple example &#8211; you need to create a chat application [...]]]></description>
			<content:encoded><![CDATA[<h3>Ajax is not as powerful as one would imagine</h3>
<p>If you have ever tried to develop a robust ajax application, you have probably reached a point where you want the client to be notified about a change on the server in &#8220;real time&#8221;. The most simple example &#8211; you need to create a chat application and want the client to instantly receive new messages upon their arrival on the server. And, if you like me, are not a fan of Flash ( which may be one of your major flaws ) and want to achieve this using only ajax techniques, you have found out that is not that simple. <span id="more-3"></span></p>
<h3>There is no real channel between the server and the client</h3>
<p>In that case you have no real permament connection between the server and the client and there is no real way of &#8220;triggering&#8221; events or sending data from the server to the client in any traditional way. Moreover, ajax does not support the client &#8220;listening&#8221; and waiting for a server&#8217;s call ( well, that&#8217;s a client after all ). You googled for some time, asked some fellow developers and almost all you could find was &#8211; &#8220;Just use javascript&#8217;s (notorious) setTimeout() or setInterval() function to repeatedly poll the server and check whether there is new data for the client&#8221;.</p>
<p>Like, for example ( using jQuery ) :</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> read<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  jQuery.<span style="color: #660066;">ajax</span><span style="color: #009900;">&#40;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #3366CC;">'url'</span>     <span style="color: #339933;">:</span> <span style="color: #3366CC;">'chat/read/'</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">'cache'</span>   <span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">'dataType'</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">'json'</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">'success'</span> <span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>messages<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      <span style="color: #006600; font-style: italic;">//if there are new messages - write them on the wall</span>
      <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span> messages <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
	<span style="color: #006600; font-style: italic;">//write messages to the chat wall</span>
      <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
setTimeout<span style="color: #009900;">&#40;</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span> read<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">2000</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>( I will not show any server-side code examples as they are simple enough &#8211; the method being /chat/read/ would just read from the database and return new records. Moreover, what we have here <strong>is not</strong> what we&#8217;re trying to achieve &#8211; the example here is for descriptive purposes only. )</p>
<p>Is that what we call highly-responsive, flexible applications, you&#8217;d ask? No. This technique has several drawbacks:</p>
<ul>
<li>it sends http requests from the client to the server and gets response ( most of the time empty ones ) on every X number of seconds. X usually is a far too small number and that can translate into way too much wasted bandwidth, if we are talking about a high-traffic website and if we need that polling done for multiple actions</li>
<li>it can eventually make the client hang-up as most modern browsers ( except for Chrome &#8211; or at least &#8211; what Chrome pleads ) don&#8217;t have smart javascript garbage collection and all those requests can be quite costly.</li>
<li>it is not really highly-responsive &#8211; it has a lag of 2 seconds which may be enough to make the users nervous</li>
<li>this just doesn&#8217;t feel like the right way of doing things</li>
</ul>
<h3>Comet</h3>
<p>Well, I need to be honest &#8211; the <a  title="Comet" href="http://en.wikipedia.org/wiki/Comet_(programming)" target="_blank">Comet</a> technique ( also known as <strong>long-polling</strong> ) seems like nothing new but I personally was not aware of it&#8217;s power till recently ( <a  href="http://pagebakers.nl">Eelco</a> pointed it to me ). But you will be amazed how many open- and closed-source projects have no idea that it is out there and do not try to use it. And it is simple &#8211; you make a request to the server, it gets it and just&#8230; <em>waits</em>. Waits till there is meaningful data to be returned or returns something less useful ( like null ), if the request is about to timeout. On a standard apache configuration that would mean 5 minutes &#8211; <strong>you can make just one single request on every 5 minutes</strong>, not on every 2 seconds ( which a traditional ajax app would do ). That is 150+ times less requests, less bandwidth, less javascript functions&#8217; calls and the application would feel <strong>much more responsive</strong>.</p>
<p>There is, however, a small side note to mention&#8230;</p>
<h3>PHP Sessions are not keen on long-polling</h3>
<p>And, if you hadn&#8217;t read this post, you&#8217;d have had some hard time finding this out. It is just that in every normal application, you can be 97% sure you will be using sessions. And in most of the time, you will rely on the built-in php sessions&#8217; handler. So far, so good. But the small problem is that you cannot simultaneously be running different scripts ( or more than one instantiation of a script ) which use one and the same user session ( that, again, was a discovery by <a  href="http://pagebakers.nl">Mr. Pagebaker</a> ). PHP will just queue all subsequent requests which try to interact with that session, until the first one has been closed. Well, that is not much of an <em>asynchroneous</em> technique either then. Getting back to our chat application &#8211; if you want to long-poll the server and wait for new messages ( what we will call read() ) and simultaneously send new messages to the server ( write() ), the application will not write() until the read() request has finished ( which we have set to 5 mins, if in the worst case there is no new data to be received ) &#8211; that is absolutely not what we need.</p>
<h3>Frameworks to the rescue</h3>
<p>But, as all self-respectful developers, you have adopted a php framework which provides an alternative to the native php sessions&#8217; handler &#8211; be it file, database or any other geeky approach. I&#8217;d prefer CakePHP where it is simple &#8211; just open your /app/config/core.php and find</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">Configure<span style="color: #339933;">::</span><span style="color: #004000;">write</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Session.save'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'php'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>change that to</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">Configure<span style="color: #339933;">::</span><span style="color: #004000;">write</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Session.save'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'database'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>and uncomment the few lines below that line with respective data.</p>
<p>So, now let&#8217;s see what we have:</p>
<p>Our client-side script ( jQuery again ):</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">function</span> read<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  jQuery.<span style="color: #660066;">ajax</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #3366CC;">'url'</span>     <span style="color: #339933;">:</span> <span style="color: #3366CC;">'/chat/read/'</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">'cache'</span>   <span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">'dataType'</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">'json'</span><span style="color: #339933;">,</span>
    <span style="color: #3366CC;">'success'</span> <span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>messages<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span> messages.<span style="color: #660066;">length</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
	<span style="color: #006600; font-style: italic;">//write to chat wall</span>
      <span style="color: #009900;">&#125;</span>
      read<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>It is important to notice that even though I have not shown the write() function, you should use <a  href="http://plugins.jquery.com/project/ajaxqueue">jQuery&#8217;s Ajax Queue Plugin</a>, so that our write requests are kept in good order. That is not needed when we read() as no subsequent read() requests will be fired before the first one has ended.</p>
<p>And, our cakephp chat controller method:</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> read<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
  <span style="color: #000088;">$lastMessage_id</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Session<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>read<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Conversation.lastMessage_id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$lastMessage_id</span> <span style="color: #339933;">===</span> <span style="color: #009900; font-weight: bold;">null</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Json<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>encode<span style="color: #009900;">&#40;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Session<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>write<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'Conversation.lastMessage_id'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #990000;">exit</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
  <span style="color: #000088;">$now</span> <span style="color: #339933;">=</span> <span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000088;">$timeout</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">300</span><span style="color: #339933;">;</span>
  <span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">connection_aborted</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$messages</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Conversation<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>read<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$lastMessage_id</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span><span style="color: #990000;">empty</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$messages</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Session<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>write<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">'Conversation.lastMessage_id'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$messages</span><span style="color: #009900;">&#91;</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$messages</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'Message'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'id'</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Json<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>encode<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$messages</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #990000;">exit</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span> <span style="color: #990000;">time</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;</span>gt<span style="color: #339933;">;</span> <span style="color: #000088;">$now</span> <span style="color: #339933;">+</span> <span style="color: #000088;">$timeout</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">echo</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>Json<span style="color: #339933;">-&amp;</span>gt<span style="color: #339933;">;</span>еncode<span style="color: #009900;">&#40;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
      <span style="color: #990000;">exit</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #990000;">sleep</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>In short &#8211; we get the last message id from the user session then use it to fetch newer records from the model. If there are none and the user hasn&#8217;t left our webpage, we start looking for new messages once again and so on. We also keep track on the time we have spent so far in that iteration &#8211; we don&#8217;t want an ugly timeout, that is why we just send an empty response, if we have reached a critical level ( $timeout = 300 in that case ).</p>
<p>For simplicity, I do not use views in that example but it is highly recommended that you avoid using the JSON component and use views instead ( who knows, you might need a different format in the future ).</p>
<p>Notice the sleep(1) line &#8211; we don&#8217;t want our CPU to burn out after a few hours of work, so some time for rest is highly recommended. You may, of course, use smaller intervals but at your own risk.</p>
<p>That is it for now &#8211; feel free to comment and thanks for reading <img src='http://www.ovalpixels.com/blog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.ovalpixels.com/blog/2008/11/15/highly-responsive-ajax-applications-without-excess-bandwidth-waste/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

