Overriding caching limitations with Javascript

I’ve mentioned some times monitor.vrypan.net, my greek blogs agregator (and search engine too now!). One of the problems I had was that page generation is very demanding in CPU cycles and memory (many SQL queries, and some recursive functions). The obvious solution is caching which is actualy a good one in this case since I know when I update data (fetch new feeds), and in between nothing changes.

However, I wanted to add some personalization by highlighting new posts for each visitor. This means that each visitor would see a different page, depending on when was his last visit. How can this be done on a cahced page? An elegant solution I found was to use a dynamicly generated Javascript do do some “ajustements” to the cached page, after it is loaded.

Here is how.

Firts of all, all posts, are inserted in a table named monitor_posts. This table has a unique id column. So what I would need to do was to set a cookie with the last ID shown, then next time highlite entries with a bigger id.

The generated (and cached) html has entries like <div id=”ITEM_xxxxx” ><div id=”TITLE_xxxxx”>post title</div> …more html here… </div> where xxxxx is monitor_posts.id. I wrote a PHP script that dynamicly generates a javascript file, mark_new.php, that looks like this:
&lt;?
if ($_COOKIE['lastID']) $lastID=$_COOKIE['lastID'] ;
else $lastID=0 ;

$db = DB::connect($DSN);
if (DB::isError( $db )) {
echo DB::errorMessage($db);
die() ;
}

$res = $db-&gt;query("SELECT MAX(id) AS M FROM monitor_posts") ;
$row=$res-&gt;fetchRow(DB_FETCHMODE_ASSOC) ;
$newID = $row['M'] ;

echo "
function mark_new_posts() {
var MaxID=" . $lastID . " ;
var main = document.getElementById('main') ;
var i ;
var j ;
var items ;
var feed ;
var title ;
for (i=0; i&lt;main.childNodes.length; i++) {
feed = main.childNodes[i] ;
for (j=0; j&lt;feed.childNodes.length; j++) {
if (feed.childNodes[j].id &amp;&amp; feed.childNodes[j].id.substring(0,5)=='IITEM') {
itemID = feed.childNodes[j].id.substring(6,38) ;
if (parseInt(itemID)&gt;MaxID) {
title=document.getElementById('TITLE_'+itemID) ;
title.style.color = '#aa0000' ;
}
}
}
}
SetCookie('lastID', '" . $newID . "') ;
}
" ;
?&gt;

Then I include the dynamicly generated js file in my “static” cached page:
&lt;script language="JavaScript" type="text/javascript" src="mark_new.php"&gt;&lt;/script&gt;

and I call it “onLoad”:
&lt;body onload="mark_new_posts();" &gt;

Obviously, the generation of the js file by PHP is not so demanding, the 2 queries performed are fast. And of course, you could have used the same technique based on a session that involves user authentication, etc.

Don’t stick to details as why do you traverse the whole DOM tree and not… This is a specific example for a specific application, with its own quirks and twists. What I find interesting in this solution is how you can use server-side caching to serve a “generic” HTML page and then use it as a canvas to draw on it with a dynamicaly generated Javascript that adds personalization or other features.

Comments are closed.