210 likes | 362 Views
Caching to improve performance. http://www.flickr.com/photos/jamescridland/613445810. Overview of caching. After you get a result, save it so you don't have to get it again Examples Finding the maximum of many different numbers Or any other expensive mathematical computation
E N D
Caching toimprove performance http://www.flickr.com/photos/jamescridland/613445810
Overview of caching • After you get a result, save it so you don't have to get it again • Examples • Finding the maximum of many different numbers • Or any other expensive mathematical computation • Generating a really nicely-formatted image • Or any other expensive formatting computation
Key steps in caching • Define a variable for storing the result • If the variable does not yet have a value • Do whatever is needed to compute the result • Assign the result to your variable • Use the value of the variable
Pros and cons of caching • Pros: • Caching eliminates the need to recompute • Cons: • Caching requires some storage to store values (such as RAM, or some hard drive space) • Caching gives no benefit unless the value is reused
When and when not to cache • Do cache when • A value is very expensive to compute or get, AND • And that value will be needed many times • Do not cache when • The result is not expensive to get, OR • The result will only be needed once, OR • There isn't enough storage available to cache
Caching works at every level!!! Web server Database or files Web page UI Your AJAX code Cache in JS variable Cache in browser Cache in session Cache in DB/files
Examples of expensive JS computations • Retrieving a piece of data from the server • Such as retrieving a JSON object or XML file • Network round-trips are probably the slowest computation you can do! • Prompting the user for some input • E.g., if you have a site for browsing different schools' courses, ask the user once what school he or she wants to look at • From the user's standpoint, giving input is an "expensive" operation.
Detailed example of JS caching <script src="jquery-1.8.2.min.js"></script> <script> varteamCache = {}; function getPlayers() { var team = $("#team").val(); if (teamCache[team]) fillin(teamCache[team]); else $.ajax({ url:"team"+$("#team").val()+".json", dataType:"json", error:function() {alert("Cannot retrieve.");}, success:function(result) { if (result && result.players) { teamCache[team] = result.players; fillin(result.players); } else { alert("No data provided."); } } }); } function fillin(playerlist) { $("#players").text(playerlist+""); } </script> <select id="team" onchange="getPlayers()"><option value="">--Choose--</option> <option value="1">Team Alpha</option><option value="2">Team Beta</option></select> <div id="players"></div> You need a JS variable. If you might be storing multiple values, then use an associative array. Index your array with a key. Check if your value is already saved. If so, just use it. Otherwise, just do your expensive computation Remember to save your result for reuse later on!
Caching in the browser • Your AJAX code doesn't need to hit the server every single time. • $.ajax({}) accepts a cache option • Tells AJAX to automatically cache every GET request in the browser's cache • By default • cache == true for most versions of Internet Explorer • cache == false for most other versions of browsers
Example of AJAX request to cache <script src="jquery-1.8.2.min.js"></script> <script> function getPlayers() { $.ajax({ url:“team"+$("#team").val()+”.json”, dataType:"json", cache:true, error:function() {alert("Cannot retrieve.");}, success:function(result) { if (result && result.players) { fillin(result.players); } else { alert("No data provided."); } } }); } function fillin(playerlist) { $("#players").text(playerlist+""); } </script> <select id="team" onchange="getPlayers()"><option value="">--Choose--</option> <option value="1">Team Alpha</option><option value="2">Team Beta</option></select> <div id="players"></div> Wow, just one line of code.
More control over browser caching • Your server exerts some control over caching • Server can specify that a certain page • Should NOT be cached at all • Should INDEED be cached if possible • Should INDEED be cached if possible, but only for a certain amount of time • Should cache in even more complex ways (that you probably don't need to know, for now) • All of these OVERRIDE your AJAX cache param • All these apply also to the web page
All these apply also to the web page • When your PHP generates some HTML, the PHP can send a cache control header • So that the browser caches the page (or not) • ALSO works very nicely for JS and CSS • Put your JS and CSS in another PHP file • At the top of your PHP file, send headers • Link with your main page with <script> and <link>
Server telling browser NOT to cache JSON (server-side) <?phpheader("Expires: Tue, 1 May 2012 10:00:00 GMT"); // in the past header("Cache-Control: no-cache"); echo '{"players":["Chet","Emelia","Rob","Tami"]}'; ?> <?php header("Expires: Tue, 1 May 2012 10:00:00 GMT"); // in the past header("Cache-Control: no-cache"); ?> <html><body><?php echo time()."" ?> <a href="mydata.php">test</a></body></html> HTML (server-side)
Server telling browser INDEED to cache JSON (server-side) <?php $nsecs = 7*24*60*60; // 7 days in the future header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time()+ $nsecs),true); header("Cache-Control: public, max-age=$nsecs",true); ?><?php echo '{"players":["Chet","Emelia","Rob","Tami"]}'; ?> <?php $nsecs = 7*24*60*60; // 7 days in the future header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time()+ $nsecs),true); header("Cache-Control: public, max-age=$nsecs",true); ?> <html><body><?php echo time()."" ?> <a href="mydata.php">test</a></body></html> HTML (server-side)
Caching in proxy servers • Remember that there might also be proxy servers between the browser and the server • The http headers shown in the preceding slides will also control caching by proxies • This will affect all users behind those proxies • There are also http headers you can use to control just browsers or just proxies • Under some circumstances, http cache headers are ignored • E.g., if user clears the cache, or runs out of space, or if the request is an http POST
Summary so far • You can store results in JS variables • Takes some code, but you have lots of control • http-based caching • Can be specified with 1 line of JS in AJAX code • Can be specified with 2 lines of PHP on server • Can be used to control browser or proxy caching • Might be disregarded
Moving to the server…Examples of expensive computations • Retrieving data from the database • Such as retrieving a list of records • Especially if you need to join multiple tables or do an aggregate query • Formatting data as HTML • E.g., if you have a site for browsing different schools' courses, generate the HTML once and cache it
Where should results be cached? • If the results are only needed by one user • If the results are needed in the client • Then cache in JS or browser (http headers) • Else • Cache in the PHP session • Else • Cache in the database or a file on the server
Example of caching in the session <?php session_start(); $teamdflt = (isset($_SESSION['team'])) ? $_SESSION['team'] : ""; ?> <script src="jquery-1.8.2.min.js"></script> <script> function getPlayers() { $.ajax({ url:"mydata.php?team="+$("#team").val(), dataType:"json", cache:true, error:function() {alert("Cannot retrieve.");}, success:function(result) { if (result && result.players) { fillin(result.players); } else { alert("No data provided."); } } }); } function fillin(playerlist) { $("#players").text(playerlist+""); } $(document).ready(getPlayers); </script> <select id="team" onchange="getPlayers()"><option value="">--Choose--</option> <option value="1">Team Alpha</option><option value="2">Team Beta</option></select> <div id="players"></div> <script>$(document).ready(function() {$("#team").val(<?php echo $teamdflt ?>);});</script> <?php session_start(); $_SESSION["team"] = $_REQUEST['team']; echo '{"players":["Team' . $_SESSION["team"] . '","Chet","Emelia","Rob","Tami"]}'; ?> mydata.php
Example of caching in files <?php ini_set('display_errors', 'On'); $mysql_handle = mysql_connect('oniddb.cws.oregonstate.edu', 'scaffidc-db', 'tzBs5Bf8uDAAvqiK') or die("Error connecting to database server"); mysql_select_db('scaffidc-db', $mysql_handle) or die("Error selecting database: $dbname"); mysql_query("drop table player"); mysql_query("create table player(pid integer, tid integer, pnamevarchar(20), primary key(pid))"); mysql_query("insert into player(pid, tid, pname) values(1,1,'Jim')"); mysql_query("insert into player(pid, tid, pname) values(2,1,'Carrie')"); mysql_query("insert into player(pid, tid, pname) values(3,1,'Karen')"); mysql_query("insert into player(pid, tid, pname) values(4,1,'Chris')"); mysql_query("insert into player(pid, tid, pname) values(5,2,'Kecia')"); mysql_query("insert into player(pid, tid, pname) values(6,2,'Pablo')"); mysql_query("insert into player(pid, tid, pname) values(7,2,'Monty')"); mysql_query("insert into player(pid, tid, pname) values(8,2,'Becca')"); $team = isset($_REQUEST["team"]) ? $_REQUEST["team"] : ""; if (!preg_match('/^[0-9]+$/', $team)) echo '{"players":["none '.$team.'"]}'; else { $filename = "team".$team.".txt"; // note, this should be a .txt; do NOT use .php; we will discuss in the security lecture if (file_exists($filename)) { echo file_get_contents($filename); } else { $rs = mysql_query("select * from player where tid = " . $team); $nrows=mysql_numrows($rs); $rv = '{"players":['; for ($i = 0; $i < $nrows; $i++) { if ($i > 0) $rv .= ','; $rv .= '"'. htmlspecialchars(mysql_result($rs,$i,"pname")) . '"'; } $rv .= ']}'; echo $rv; // FYI, see also file_put_contents $file = fopen($filename,"w"); fwrite($file, $rv); fclose($file); } } mysql_close(); ?> Check if file exists; Read & return if so. Otherwise, performthe expensive computation. Then put theresult in the cache.
Caching in the database • You could also define a blob and store the JSON string in the database • This is left as an exercise for you, if you like.