In: Categories » » AJAX » Managing the Data Using a Client Cache using Ajax
Managing the Data Using a Client Cache The application performance depends on the caches that are implemented on the client and server sides. If the caches perform poorly, the application will perform poorly. If the caches are effective, the application will be effective. To a large degree, what I just said is obvious, but I want to stress that no matter how well written the other parts of your code are, if you have a bad caching strategy, the application will perform poorly. Four types of caching strategy can be implemented:
• HTTP validation: A form of caching where the client and browser share information about a URL using a handshaking protocol. This form of caching does not reduce the conversation counter, but it does reduce how much data is sent in the conversation. Use this approach if you have data that changes regularly and your network connection between the client and server is of broadband quality.
• Client-side only: A form of caching where only the client side caches the information. Typically, you use this approach when the server does not support caching, or if the round-trip between the client and server requires too much time.
• Server-side only: A form of caching where only the server side caches the information. The client will constantly query the server for the appropriate information. This form of cache is generally inefficient, and it should be used only if the physical network distance between the client and server is minimal (e.g., the browser and server are on the same computer).
• Client and server side: A generalized ideal way of caching where both the server and the client cache information. In each of these caching strategies, you need to think about the available bandwidth, what kind of data you are receiving, and how far apart the client is from the server. An additional worry is the proxies sitting between the client and server that could cache the information.
Implementing a Single Request Client Cache An effective and efficient cache would not change the programming model of the client. Therefore, a client-side cache is best implemented by modifying the Asynchronous class. Then whenever some code uses Asynchronous, the cache is checked and verified to see if the response is already available. If the response is available, then the code receives the response immediately. The following example has hooks to make use of a cache.
Source: /client/scripts/jaxson/common.js
function Asynchronous_call(request) {
var instance = this;
if (! this.settings) {
throw new Error("Settings is not defined ");
}
if (this.xmlhttp.readyState != 4 && this.xmlhttp.readyState != 0) {
throw new Error("Currently active request cannot continue");
}
this.xmlhttp.open(request.action, request.url, true,
this.settings.username, this.settings.password);
globals.info("Opening request " + request.url);
if (request.headers) {
for( defHeader in request.headers) {
this.xmlhttp.setRequestHeader(defHeader, request.headers[defHeader]);
}
}
if (this.settings.headers) {
for( defHeader in this.settings.headers) {
this.xmlhttp.setRequestHeader(defHeader,
this.settings.headers[defHeader]);
}
}
this.settings.url = request.url;
if (this.cache.processAndBreakBeforeRequest(this.xmlhttp,
request, this.settings) == true) {
globals.info("Retrieved data from cache for request " +
instance.settings.url);
return;
}
this.xmlhttp.onreadystatechange = function() {
if (instance.xmlhttp.readyState == 4) {
globals.info("Received data for request " + instance.settings.url);
if (instance.cache.processAndBreakAfterRequest(instance.xmlhttp,
request, instance.settings) == true) {
return;
}
try {
instance.settings.onComplete(instance.xmlhttp);
}
catch (e) {
globals.errorHandler(e);
}
}
}
try {
this.xmlhttp.send(request.data);
}
catch( e) {
globals.errorHandler(e);
}
}
The Asynchronous code is very similar to what was presented in Article 4. The new parts are in bold. Hooking a cache into Asynchronous is easy: you need to capture the request before it is sent, and then capture the response when it arrives. Asynchronous does not implement a cache, because there are many ways to code a cache. The smartest strategy, and the one chosen by Asynchronous, is to delegate the calls to another method. In the case of capturing a request, the this.cache.processAndBreakBeforeRequest method is called. The XMLHttpRequest, request, and settings of the Asynchronous instance are passed to the method. If the method returns true, then Asynchronous_call returns immediately. The immediate return usually indicates that data is in the cache, but it can also be used to stop a request.
In the case of capturing a response, within the implementation of onreadystatechange is a request to the instance.cache.processAndBreakAfterRequest method. Three parameters are passed to the method: an XMLHttpRequest instance, request, and settings. Based on those three parameters, the cache can store the response data to be retrieved at a later point. If the processAndBreakAfterRequest method returns true, then the response data is not sent to the onComplete method. Generally speaking, you would not do this, but it is necessary if you are implementing an HTTP validation cache.
The type of cache that you want to implement depends on your needs. It can be either a client-side cache or an HTTP validation cache. In the context of the stock ticker application, a single request client cache is created. The single request client cache will cache every request once and never make a second physical HTTP request. This is fine for the case of the stock ticker example, because the historical ticker data never changes. If the data were to change, you would need to have a way of indicating stale data. In such a case, an HTTP validation cache would be more appropriate. The following code is the implementation of a single request client cache.
Source: /client/scripts/jaxson/common.js
var CacheController = {
_cache : new Array(),
}
function CachedProcessAndBreakBeforeRequest(request, settings) {
if (request.action == "GET") {
var obj = CacheController._cache[settings.url];
if (obj != null) {
var fakeXMLHttp = {
status : 200,
statusText : obj.StatusText,
responseText : obj.ResponseText,
responseXML : obj.ResponseXML
}
try {
settings.onComplete(fakeXMLHttp);
}
catch (e) {
globals.errorHandler(e);
return false
}
return true;
}
}
return false;
}
function CachedProcessAndBreakAfterRequest(xmlhttp, request, settings) {
if (xmlhttp.status == 200 && request.action == "GET") {
CacheController._cache[settings.url] = {
Status : xmlhttp.status,
StatusText : xmlhttp.statusText,
ResponseText : xmlhttp.responseText,
ResponseXML : xmlhttp.responseXML
};
}
return false;
}
The single request client-side cache operates only when the HTTP GET is called, which is completely logical but does beg the question of whether a POST, DELETE, or PUT can be cached. The answer is, yes they can, if the cache is intelligent. For example, if you were to cache a PUT, then when the same URL is called using GET, you don’t need to query the server. This strategy can get you into trouble if there is a chance that multiple users will be executing a PUT. But there is an optimization in that you can spin off a JavaScript thread and query the status of the data sent by the PUT using HTTP validation. It’s important to realize that you can tune the cache to suit your preferences. You could even tune the cache such that it can preload URLs when certain URLs have been requested.
The single request client-side cache is not that intelligent and returns an object if it exists in the cache; otherwise, it queries the HTTP server. The CachedProcessAndBreakBeforeRequest function is called before Asynchronous makes a physical request. When the function is called, the existence of the URL is tested in the CacheController._cache object. If the URL does not exist, then false is returned, indicating that the URL should be executed. If the URL does exist, then a cached object exists. The existence of a cached object means that it is not necessary to call the server, and the code’s onComplete method can be called directly. The only problem with the cached object is that there is no available XMLHttpRequest instance.
The solution to this problem is to create a fake instance of XMLHttpRequest. Using JavaScript, it’s easy to create a fake object. Where things get tricky is that the methods have not been defined, thus they are not available. The headers are not available because they have not been stored in the object when the cached object was created. Again, the fact that the headers have not been stored in the cache highlights that this is a simple implementation of XMLHttpRequest. The fakeXMLHttp variable represents the fake XMLHttpRequest object and is used to call the code’s settings.onComplete method. Because settings.onComplete is called, the cache returns a false value, indicating that Asynchronous should not make an HTTP request.
The other part to the cache code is the CacheProcessAndBreakAfterRequest function, which is used to add a cached object entry. The addition of the object to cache is constrained to an HTTP status code of 200 and an HTTP GET. If the object is added to the cache, then the XMLHttpRequest property, status, statusText, responseText, and responseXML are saved. If you wanted to create a complete implementation of the fake XMLHttpRequest object and save the HTTP headers, you would put that code in the CacheProcessAndBreakAfterRequest function. As an alternative, you might be tempted to save a reference to the XMLHttpRequest instance. The problem is that the cache is not in control of the XMLHttpRequest instance, so by saving a reference, you are not saving the data, as the Asynchronous instance could reuse the XMLHttpRequest instance for another request. Therefore, whenever implementing your cache, you need to copy the information that should be saved in the cache.
Implementing an HTTP Validation Client Cache The cache implementation is simple in that once a request has been executed and saved, it will never be executed again. For URLs where the data never changes, this is acceptable. However, there are URLs where the data changes, such as is the case with a real-time stock ticker, and the single request client cache is completely unacceptable. In those situations, the single request client cache needs to be extended to use HTTP validation.
HTTP Expiration Caching Is a Bad Idea (Generally) When you are using HTTP validation, you are letting the Internet infrastructure manage the caching. There are two models: HTTP expiration and HTTP validation. When using HTTP expiration, you are saying that content is valid for a certain period of time. The period of time for which the data is valid depends on what the HTTP headers say. It is generally not a good idea to use the HTTP expiration model; rather, it’s better to use HTTP validation and write code to help the Internet infrastructure do its work. To understand why the HTTP expiration model is problematic, consider the following scenario. Say you are running aWeb site that hosts news feeds. To reduce repetitive traffic on the Web site, you enable HTTP caching and assign an expiration time of 30 minutes. (The expiration time is an arbitrary value used for illustrative purposes.) This means that when a browser downloads some content, the next version of the content will be available in 30 minutes. Indicating a wait period of 30 minutes is a bad idea in that 30 minutes, news can dramatically change.
A client who has downloaded some content is then restricted to retrieving news in 30-minute cycles. Of course, the client could ignore or empty the cache, resulting in downloads of the latest information. If the client always empties the cache, the client will always get the latest news, but at a cost of downloading content that may not have changed. The resource cost should not surprise anyone, because always getting the latest content means using no caching whatsoever. Scripts such as Java servlets/JSP or ASP.NET pages often use this strategy, and the administrator managing the Web site wonders why there are performance problems.
legal notice
Our website is not responsible for the information contained by this article. Web-articles is a free articles resource.
Suggestion: If you need fresh, daily updated content for your website, feel free to use our service. Click here for more information.
Useful tools and features
related articles
Given the recent interest in Ajax, you’d be forgiven for thinking it was a new technology. In fact, the XMLHttpRequest object has been around for years. In technical terms, asynchronous JavaScript interaction with the server is nothing new. All of the other elements of the Ajax model have also been around for quite some time: CSS, (X)HTML, and DOM Scripting. Yet in 2005, interest in this methodology soared. Could it really be that simply giving this approach a snappy name like Ajax was responsible for the sudde...
2. Understanding the Definition and Philosophy of Ajax
The focus of this article is to provide solutions to some common, general problems and questions that are bound to arise before or during development of Asynchronous JavaScript and XML (Ajax) and Representational State Transfer (REST) applications. These common questions are not always technical in nature, often leaning more toward theory or philosophy of development. The problem with these kinds of questions is that once you begin to think about them, you keep going in a circle and end up where you star...
3. Understanding the Definition and Philosophy of Web Services and SOA
Understanding the Definition and Philosophy of Web Services and SOA Wikipedia offers the following definition of Web services:4 The W3C defines aWeb service as a software system designed to support interoperable machine-to-machine interaction over a network. This definition encompasses many different systems, but in common usage the term refers to those services that use SOAPformatted XML envelopes and have their interfaces described by WSDL. For ex...
4. Understanding the Definition and Philosophy of REST
Understanding the Definition and Philosophy of REST REST is a controversial topic among Web service enthusiasts, because it’s considered to stand for the opposite of what Web services and SOA are trying to achieve. The problem with this thinking is that REST is not in contradiction with the abstract definition of SOA and Web services. REST is in contradiction with technologies such as SOAP, WSDL, and WS-* specifications. The following offers a quick definition of REST:...
5. The Easiest Way to Get Started with Ajax and REST
The Easiest Way to Get Started with Ajax and REST Problem You want to know the best way to get started with writing Ajax and REST. Solution When developing an Ajax and REST application, you must decide on the tools and frameworks you’ll use. The choice is simple: Use whatever you’re using today, and write some Ajax applications. You don’t need to change the tools you’re using today. Whether you’re using ASP.NET, JavaServer Pages (JSP), PHP, Ruby, or Python, you...
6. Testing a Dynamic Contract with Ajax
Coding the Contract Using Test-Driven Development Techniques Coding the contract using agile and test-driven development techniques requires writing a number of tests and implementing aMock URL layer. Problem You want to code the contract using these development techniques. Solution To demonstrate, let’s define a use case, implement the use case as a contract, write a test case(s) to implement the contract, implement the contract in the Mock URL, and finally...
7. Testing the Client Side Logic
Problem You want to effectively test your application’s client-side logic. Theory Testing GUI code tends not to be a productive task because of the complications that arise. The main complication is how to test the correctness of a user interface. Imagine a situation where clicking a button causes a table to be filled with data. Now imagine that when a check box is checked and the button is clicked again, a different table is filled with content. The fact that clicking the same button results in two ...
8. Understanding JavaScript and Types
Understanding JavaScript and Types Problem You want to work around the fact that JavaScript does not have types declared for its variables. Theory JavaScript code does not have any variables with a declared type. The lack of typed variables is apparent when you declare functions. That said, not having typed variable declarations does not mean JavaScript has no types or no type safety. Let’s start out with the simple declaration of a function, as illustrated by the following ex...
9. Coding Using Conventions and Not Configurations
Coding Using Conventions and Not Configurations Problem You want to make your JavaScript constructs more efficient by applying the Rails “convention over configuration” principle to them. Theory You may already be familiar with the programming platform Ruby on Rails, which is used to build Web applications. The focus of this recipe is not Ruby on Rails, but one aspect of Ruby on Rails namely, convention over configuration (see http://en.wikipedia.org/wiki/ Ruby_on_Rails for m...
