Performance: Caching static data on Client Side

Recently one of my friends came to me with a performance issue. They are doing some sort of mapping application (Building Locator) using Microsoft Virtual Map. They have one search screen where they can feed in their country name, state etc... and they make AJAX calls for fetching data which is then plotted on the map.
First I checked their database and found it takes at-least one minute to fetch the data for each search. We can't do anything on the DB side because of other reason.
The plus point I have noticed here is data will be static almost all the time but may vary once in a while (once in a year may be). So our idea was to bring the entire data to the client side (but not putting them to client's memory always). We thought of using globalStorage mechanism, added in HTML 5 (only few browsers support this now) or JSCache, but skipped because of the data load.
We tried using Dynamic Java Script for caching static data on the client machine. With this approach the data are send to client side as a JavaScript file and will be stored in their IE Temporary Folder. So we don't have any memory Constrains there. Also like Cookie, the data are not passed with each request/response. One more advantage we felt here is, this feature not only store data, but do more on functionality side. To make clear let us see how we did this,
1. Writing Server Side Component (I am using Java here - You can use any language)
public class JSServlet extends HttpServlet {

protected void doGet(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
StringWriter buffer = new StringWriter();
prepareData(buffer);

String encoding = request.getHeader("Accept-Encoding");
boolean supportsGzip = false;

if (encoding != null) {
supportsGzip = (encoding.toLowerCase().indexOf("gzip") > -1);
}
if (supportsGzip == true) {
response.setHeader("Content-Encoding", "gzip");
response.setHeader("Content-Type", "text/javascript");

try {
GZIPOutputStream gzos = new GZIPOutputStream(response
.getOutputStream());
System.out.println(buffer.getBuffer().toString());
gzos.write(buffer.getBuffer().toString().getBytes());
gzos.close();

} catch (IOException ie) {
}
} else {
// You output ordinary HTML here
// when GZIP is not supported by the browser.
}
}

private void prepareData(StringWriter buffer) {
Employee emp1 = new Employee(111, "Biju", "Nair", 35);
Employee emp2 = new Employee(121, "Chellappa", "Murugan", 32);
//json.org
JSONObject[] empArray = { new JSONObject(emp1), new JSONObject(emp2) };

JSONArray jsonArr = null;
buffer.write("function displayName(empid){ ");
buffer.write("\nvar employeeObject = {\"empList\" :");
try {
jsonArr = new JSONArray(empArray);
jsonArr.write(buffer);
} catch (JSONException e) {
}
buffer.write("};");
buffer.write("\nfor(index=0;index<employeeObject.empList.length;index++){");
buffer.write("\n if(employeeObject.empList[index].empid == empid){");
buffer.write("\n alert('Name: '+(
employeeObject.empList[index].lastName+',
'+employeeObject.empList[index].firstName));");
buffer.write("\n break;");
buffer.write("\n }");
buffer.write("\n}");
buffer.write("\n}");
}
Since we have used HTTP 1.1 GZip compression on the response, the data send from server to client is minimal.

2. Writing Client Side Component


<html>
<head>
<script type="text/javascript" src="JSServlet">
</script>
</head>
<body>
<form name='frm'>
Enter Employee ID:<input type='text' name='empid'>
<input type='Button' onClick='javascript:displayName(document.frm.empid.value)' value='Search'>
</form>
</body>
</html>



Look at the bolded lines above for the key points. In this case I have used static way of loading the data, but you can also do that using dynamic way using DHTML as,
script = document.createElement('script')
script.src = 'JSServlet';
document.heads[0].appendChild(script);


You can also restrict the data load or push to client depending on whether there has some addition to the real data.
if (!isModified)
{
response.sendError(response.HTTP_NOT_MODIFIED,
"Not Modified");
} else {
response.addHeader("Last-Modified",new Date());
...
//actual code to load data and send it to client
}

Advantages:
  • Make the UI perform fast.
  • Entire data is taken to client side, so no need for repeat server request (Ajax) for fetching data.
  • Data can be fetched during each page load (for updated data) or only once (for ever).
Caution: Don't use this approach for secured information.
I am still in the process of fine tuning the solution. Will keep you update....