1
\$\begingroup\$

I want to implement in my code a cache mechanism with a fixed duration. For example an iframe will be cached for one hour, or a script file will be cached for 24 hours.

This is how I implemented it, with a rounded timestamp (simplified code assuming that the url doesn't have any query or hash part):

var duration=86400000; // example for 1 day = 86400000 milliseconds
url=url+"?_ts="+ getTimeStamp(duration);

function getTimeStamp(roundTime) {
  var timeStamp=new Date().getTime();
  if (roundTime) {timeStamp=Math.floor(timeStamp/roundTime);}
  return timeStamp;
}

My questions:

  • Are there any traps to watch for, or is the above code going to work just fine in all situations (dynamic script tag, iframe, ajax)?
  • Is there a better way to do it, for example with a JavaScript library?
\$\endgroup\$
2
  • \$\begingroup\$ Cache at what level? \$\endgroup\$ – fge Jun 8 '13 at 20:28
  • \$\begingroup\$ @fge this is for client side JavaScript, so I am talking about browser cache. \$\endgroup\$ – Christophe Jun 8 '13 at 21:17
1
\$\begingroup\$

I suggest you read more about rules on simple rules for HTTP caching, and simple rules for AJAX caching. These should give you a heads up on gotchas, especially in IE as well as the right headers to send for HTTP caching.

A more proper way to do this is to send the right headers. This would mean some server-side action and using the Expires header.

Anyways, let's do cache busting instead. This is the method you are trying to do, which is to append a variable value into a query string. This assumes that your resources are "forever cached" and needs busting to bring in a new version.

Here's a few gotchas in your code:

  • It doesn't persist during page load.

    Since you don't have any persistence layer in your code, each page load will generate a new time stamp for the resource, and will reload them from the server instead of the cache.

  • What happens when it expires?

    I don't seem to see code that tells if the resource has already expired, unless you have other code that does that for you.

    If without it, you should build a collection that records the urls and their times. Then you refer to that collection to get the url of the resource. If the resource has not expired, then return the previously generated url. If it has expired, then generate a new url with a new time stamp and hand it for use.

Here's code that should get you on the right track. This assumes that the resources never expire, so that you need the cache-buster mechanism going.

(function(ns){

  //Read from local storage, if any, or use an empty object
  var collection = /*read from local storage*/ || {};

  ns.generate(url,duration){

    //return a runnable function that generates either an existing url
    //or a newly generated url
    return function(){
      var currentDate = Date.now();

      //if URL isn't in collection or has already expired
      if(!collection.hasOwnProperty(url) || collection[url].expires < currentDate){
        //generate the url and store
        collection[url] = {
          url : url,
          expires : currentDate + duration;
          stampedUrl : url += '?_ts='+ (currentDate + duration)
        }

        /*save in local storage*/

      }

      //return the url
      return collection[url].stampedUrl;
    }
  }
}(this.StampedUrl = this.StampedUrl || {}));

Sample usage:

//Generate and store our URL. This should return a runnable function
//that returns an unexpired URL or a newly generated url
var myScript = StampedUrl.generate('http://example.com/someScript.js',3600);

//Use function to generate the URL.
$.get(myScript(),function(){...});
\$\endgroup\$
2
  • \$\begingroup\$ Thanks for the detailed reply! I'll take a look at the links. One thing I don't agree with (and that's the point of the code): if you reload within the duration interval, the timestamp in my code will remain the same, no need to keep track of it in local storage. I have built a quick fiddle to demonstrate it: jsfiddle.net/h835X/1 . There was actually a mistake in my initial post (I used seconds instead of milliseconds), I have corrected it. \$\endgroup\$ – Christophe Jun 9 '13 at 6:31
  • \$\begingroup\$ Someone has to make the inevitable quote; might as well be me. "There are only two hard things in Computer Science: cache invalidation and naming things." – Phil Karlton \$\endgroup\$ – Flambino Nov 7 '13 at 0:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.