Treehouse

Caching AJAX Results in JavaScript

By on  
AJAX Caching!

AJAX is an awesome tool. AJAX requests are usually faster than regular page loads and allow for a wealth of dynamism within a page. Unfortunately many people do not properly cache request information when they can. Let me show you how I cache AJAX requests -- it's super easy!

My example will use my TwitterGitter plugin to grab a user's tweets. Once we have the user's tweet information, we pull it from cache instead of making a duplicate AJAX request.

The JavaScript

//our cache object
var cache = {};
var formatTweets(info) {  
	//formats tweets, does whatever you want with the tweet information
};

//event
$('myForm').addEvent('submit',function() {
	var handle = $('handle').value; //davidwalshblog, for example
	var cacheHandle = handle.toLowerCase();
	if(cache[cacheHandle] != "undefined") {
		formatTweets(cache[cacheHandle]);
	}
	else {
		//gitter
		var myTwitterGitter = new TwitterGitter(handle,{
			count: 10,
			onComplete: function(tweets,user) {
				cache[cacheHandle] = tweets;
				formatTweets(tweets);
			}
		}).retrieve();
	}
});

Note that before we make the AJAX request, we check the cache object to see if we've saved this key's (the key, in this case, is the username because it is unique) information. If so, avoid the repetitive AJAX request and simply return the cached information. If the key does not exist, make the AJAX request and save the result to the cache.

Take a look at this flow:

  • User requests "davidwalshblog" tweets. @davidwalshblog tweets don't exist in cache, so we go grab them from Twitter and store them in cache.
  • User requests "mootools" tweets. @mootools tweets don't exist in cache, so we go grab them from Twitter and store them in cache.
  • User requests "davidwalshblog" tweets again. @davidwalshblog tweets DO exist in cache, so we retrieve them from cache and avoid the ajax request.

Clearing the cache periodically is easy too!

(function() { cache = {}; }).periodical(1000 * 60 * 10); //10 minutes

Caching your AJAX results in a JavaScript object is a very simple system to implement and can save you many repetitive requests. Efficiency FTW!

ydkjs-1.png

Recent Features

  • Create Namespaced Classes with MooTools

    MooTools has always gotten a bit of grief for not inherently using and standardizing namespaced-based JavaScript classes like the Dojo Toolkit does.  Many developers create their classes as globals which is generally frowned up.  I mostly disagree with that stance, but each to their own.  In any event,...

  • 9 Mind-Blowing WebGL Demos

    As much as developers now loathe Flash, we're still playing a bit of catch up to natively duplicate the animation capabilities that Adobe's old technology provided us.  Of course we have canvas, an awesome technology, one which I highlighted 9 mind-blowing demos.  Another technology available...

Incredible Demos

  • HTML5 Context Menus

    One of the hidden gems within the HTML5 spec is context menus. The HTML5 context menu spec allows developers to create custom context menus for given blocks within simple menu and menuitem elements. The menu information lives right within the page so...

  • Introducing MooTools ScrollSide

    This post is a proof of concept post -- the functionality is yet to be perfected. Picture this: you've found yourself on a website that uses horizontal scrolling instead of vertical scrolling. It's an artistic site so you accept that the site scrolls left to right....

Discussion

  1. It should be noted that the cache is [obviously] per-client… meaning that when visitor 1 requests ABC, it will be sent and then cached locally to their browser. When visitor 2 comes along 5 seconds later, another request to ABC will be sent, and then cached to their browser as well.

    Clearing the cache (in this case, every 10 minutes) will only be useful if the client sits on the page for ten or more minutes. If I visit your site and have an AJAX request cached… when I click to another page, even within the same website, the cache will be refreshed.

    A good practical use for this would be a JavaScript-laden web app where you know the client will be on the same page for an extended period of time.

    Great tutorial!

  2. I don’t know much about the twitter api but is it possible to grab in the last tweets within the last x minutes? That way you don’t have to clear out your whole cache and grab the content that was in the cache to begin. I think this caching idea is to a good start but I think it can be greatly improved. I don’t think this is how for example gmail caches it’s mail entries. Obviously caching tweets can only be as good as the twitter api will provide, so this might be the best caching strategy given the current api.

  3. Right Jesus, but Twitter is simply my example. You could implement this system with any site or functionality.

  4. Right, I just wanted to start a discussion about other ways to do caching :). I just looked at the twitter api and it has a since_id field that you can pass in. I’m thinking that one way we can extend this caching is to add some logic before clearing out the cache. First we ask for the last tweets using the since_id field. We concatenate the results and the delete the tail end of the tweets that are over our limit. That way we are only asking for only new tweets and not tweets we already had and only deleting the tweets that we longer want.

    I realize this was just an example and I appreciate that. I would had never brainstormed if it wasn’t for this post. Good post to start the day with.

    Adding new objects to the DOM and making sure the ajax calls are queued are now two problems that get introduced with caching. IBM has a nice article using jquery to solve these two issues using the live, die calls and queue and dequeue methods, I’m not familiar with mootools but I would assume it has similiar functionality. http://www.ibm.com/developerworks/web/library/wa-aj-advjquery2/index.html

  5. In addition to what @Keith mentioned, I would also note that the cache hash is only available until another full (synchronous) request is made, at which time the cache object is destroyed. This is about the best you can do though if you only have client side control.

    If you do have server side control of the response, though, it is definitely worth setting the appropriate headers (content-expires/cache-control/eTags…) to make the browser cache the response – which can even persist across browser sessions.

    I do like this approach though for applications that are largely asynchronous, such as Google Reader. It allows you to enforce more complex caching policies than HTTP handlers do. Good article DW.

  6. @Jeremy Martin: Yep — my new website is entirely AJAX based so this caching method comes in handy bigtime!

  7. test de prueba si moderan los comentarios.

  8. Champ

    I am pretty sure that is the AJAX cleaning solution logo… just sayin

  9. The browser’s built in cache can be leveraged as well if you understand and use cache control headers properly. Of course calling other people’s APIs may not allow for that – Demo: http://ajaxref.com/ch6/builtincache.html

    In support of custom caches you might want to implement a more full fledged cache that allows you to control # of entries, push objects to it, etc. Demo: http://ajaxref.com/ch6/customcache.html

    It has been odd for me to nearly weekly notice that queues, caches, etc. are missing still from nearly every major Ajax library out but yet it was well documented in my book 2 years+ ago. with example library code. Port away if you like otherwise cool to see other people discover clear holes in Ajax!

    -Thomas

    p.s. To a previous poster the queue and sequencing issues are also easily solved…see same site Chapter 6 examples on how performed. Your tradeoff though with queues and response buffers will be performance but your results will now nearly always work assuming you have error correction, retries, etc.

  10. What does var foo = {}; Mean? I don’t understand the {} bit. Is it a regular piece of JS?

  11. @Ben: it is shorthand for creating an object.

    var foo = []; is a shorthand method of creating an array;

  12. @Keith: {} is an empty object declaration in javascript.

  13. That’s what I said, right? :)

  14. An interesting challenge, from an academic perspective at least, would be to implement a more persistent form of caching using cookies – don’t need to modify headers, but you still get content caching across browser sessions. Probably not practical for many real life uses, but would be interesting none-the-less…

  15. @Keith: Hahaha. My bad — wrong person.

  16. Connie

    Hi,

    do I understand that correctly,
    that for instance I could cache values from a mysql query which runs to fill the autosuggest-dropdown to use these values to populate other fields of the form after the autosuggested value is accepted by the user?

  17. Supposedly a user stays on a page more than 10 minutes. Then there is a chance that the user will stay more.

    Why destroy the cache then? Why not instead, use HEAD HTTP method and see if the state of the cache is still valid? If it is still valid — keep it. No need to re-fetch the same data over and over again.

    Even better, you could set up a cron that fetches the remote data every once in a while, again using HEAD to determine whether or not indeed the cache has expired and then load the data from your local file (preferably json, since it’s kinda fast). Set the reasonable expires headers accordingly to the last modified time of the local item and the update expectancy of the remote source.

    Of course, this is far from “real time” data, but then again it saves bandwidth, cuts down server load, eliminates network related issues and thus improves user experience.

    On the other hand, if indeed real-time-like feel is required, we are talking about caching and requesting on a whole new level.

  18. gel

    btw, the wp pdf plugin don’t works :D

  19. David, what happens if the page is refreshed in this case, is the cache cleared or will it be preserved?

  20. Chad

    Hey Guys

    I get cachehandle is not defined object !! any ideas???

  21. andrei cristof

    >Great stuff. Although please explain this line:

    User requests “davidwalshblog” tweets again. @davidwalshblog tweets DO exist in cache, so we retrieve them from cache and avoid the ajax request.

    They do exist in cache yes, but the cache contains his previous tweets, in order to retrieve all his tweets PLUS the latest one, you must make a new request. Am I missing something?

    Thanks

  22. [...] Caching AJAX Results in Javascript AJAX requests are usually faster than regular page loads and allow for a wealth of dynamism within the page. Unfortunately, many people do not properly cache request information when they can. The author shows you his improved method for caching AJAX requests. [...]

  23. [...] Caching AJAX Results in Javascript AJAX requests are usually faster than regular page loads and allow for a wealth of dynamism within the page. Unfortunately, many people do not properly cache request information when they can. The author shows you his improved method for caching AJAX requests. [...]

  24. [...] Caching AJAX Results in Javascript AJAX requests are usually faster than regular page loads and allow for a wealth of dynamism within the page. Unfortunately, many people do not properly cache request information when they can. The author shows you his improved method for caching AJAX requests. [...]

  25. [...] Caching AJAX Results in Javascript [...]

  26. [...] Caching AJAX Results in Javascript AJAX requests are usually faster than regular page loads and allow for a wealth of dynamism within the page. Unfortunately, many people do not properly cache request information when they can. The author shows you his improved method for caching AJAX requests. [...]

  27. Benny

    I curious if something like this can be used for a static top bar on a web page. For instance, lets say you have a web page with a top menu bar with some content that’s specific to the user that’s logged in (shows their picture, their name, etc) and that bar is shown on each page that they view on your web site. How can one avoid needing to fetch that user specific information on each and every page load? Thanks!

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!