Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Caching a jquery ajax response in javascript/browser

I would like to enable caching of an ajax response in javascript/browser.

From the jquery.ajax docs:

By default, requests are always issued, but the browser may serve results out of its cache. To disallow use of the cached results, set cache to false. To cause the request to report failure if the asset has not been modified since the last request, set ifModified to true.

However, neither of these address forcing caching.

Motivation: I want to put $.ajax({...}) calls in my initialisation functions, some of which request the same url. Sometimes I need to call one of these initialisation functions, sometimes I call several.

So, I want to minimise the requests to the server if that particular url has already been loaded.

I could roll my own solution (with some difficulty!), but I would like to know if there is a standard way of doing this.

like image 341
cammil Avatar asked Jun 14 '13 08:06

cammil


People also ask

Does browser cache AJAX requests?

Fact #1 : Ajax Caching Is The Same As HTTP Caching At this level, the browser doesn't know or care about Ajax requests. It simply obeys the normal HTTP caching rules based on the response headers returned from the server. If you know about HTTP caching already, you can apply that knowledge to Ajax caching.

What is the use of cache in Ajax?

ajax docs: By default, requests are always issued, but the browser may serve results out of its cache. To disallow use of the cached results, set cache to false. To cause the request to report failure if the asset has not been modified since the last request, set ifModified to true.

What is cache true in Ajax call?

cache:true is the default and does not always get the content from the cache. The cache-ability of an item on the browser is determined by: The response headers returned from the origin web server. If the headers indicate that content should not be cached then it won't be.

Why do we use cache false in Ajax?

The cache: false is used by developers to prevent all future AJAX requests from being cached, regardless of which jQuery method they use. We can use $. ajaxSetup({cache:false}); to apply the technique for all AJAX functions.


1 Answers

cache:true only works with GET and HEAD request.

You could roll your own solution as you said with something along these lines :

var localCache = {     data: {},     remove: function (url) {         delete localCache.data[url];     },     exist: function (url) {         return localCache.data.hasOwnProperty(url) && localCache.data[url] !== null;     },     get: function (url) {         console.log('Getting in cache for url' + url);         return localCache.data[url];     },     set: function (url, cachedData, callback) {         localCache.remove(url);         localCache.data[url] = cachedData;         if ($.isFunction(callback)) callback(cachedData);     } };  $(function () {     var url = '/echo/jsonp/';     $('#ajaxButton').click(function (e) {         $.ajax({             url: url,             data: {                 test: 'value'             },             cache: true,             beforeSend: function () {                 if (localCache.exist(url)) {                     doSomething(localCache.get(url));                     return false;                 }                 return true;             },             complete: function (jqXHR, textStatus) {                 localCache.set(url, jqXHR, doSomething);             }         });     }); });  function doSomething(data) {     console.log(data); } 

Working fiddle here

EDIT: as this post becomes popular, here is an even better answer for those who want to manage timeout cache and you also don't have to bother with all the mess in the $.ajax() as I use $.ajaxPrefilter(). Now just setting {cache: true} is enough to handle the cache correctly :

var localCache = {     /**      * timeout for cache in millis      * @type {number}      */     timeout: 30000,     /**       * @type {{_: number, data: {}}}      **/     data: {},     remove: function (url) {         delete localCache.data[url];     },     exist: function (url) {         return !!localCache.data[url] && ((new Date().getTime() - localCache.data[url]._) < localCache.timeout);     },     get: function (url) {         console.log('Getting in cache for url' + url);         return localCache.data[url].data;     },     set: function (url, cachedData, callback) {         localCache.remove(url);         localCache.data[url] = {             _: new Date().getTime(),             data: cachedData         };         if ($.isFunction(callback)) callback(cachedData);     } };  $.ajaxPrefilter(function (options, originalOptions, jqXHR) {     if (options.cache) {         var complete = originalOptions.complete || $.noop,             url = originalOptions.url;         //remove jQuery cache as we have our own localCache         options.cache = false;         options.beforeSend = function () {             if (localCache.exist(url)) {                 complete(localCache.get(url));                 return false;             }             return true;         };         options.complete = function (data, textStatus) {             localCache.set(url, data, complete);         };     } });  $(function () {     var url = '/echo/jsonp/';     $('#ajaxButton').click(function (e) {         $.ajax({             url: url,             data: {                 test: 'value'             },             cache: true,             complete: doSomething         });     }); });  function doSomething(data) {     console.log(data); } 

And the fiddle here CAREFUL, not working with $.Deferred

Here is a working but flawed implementation working with deferred:

var localCache = {     /**      * timeout for cache in millis      * @type {number}      */     timeout: 30000,     /**       * @type {{_: number, data: {}}}      **/     data: {},     remove: function (url) {         delete localCache.data[url];     },     exist: function (url) {         return !!localCache.data[url] && ((new Date().getTime() - localCache.data[url]._) < localCache.timeout);     },     get: function (url) {         console.log('Getting in cache for url' + url);         return localCache.data[url].data;     },     set: function (url, cachedData, callback) {         localCache.remove(url);         localCache.data[url] = {             _: new Date().getTime(),             data: cachedData         };         if ($.isFunction(callback)) callback(cachedData);     } };  $.ajaxPrefilter(function (options, originalOptions, jqXHR) {     if (options.cache) {         //Here is our identifier for the cache. Maybe have a better, safer ID (it depends on the object string representation here) ?         // on $.ajax call we could also set an ID in originalOptions         var id = originalOptions.url+ JSON.stringify(originalOptions.data);         options.cache = false;         options.beforeSend = function () {             if (!localCache.exist(id)) {                 jqXHR.promise().done(function (data, textStatus) {                     localCache.set(id, data);                 });             }             return true;         };      } });  $.ajaxTransport("+*", function (options, originalOptions, jqXHR, headers, completeCallback) {      //same here, careful because options.url has already been through jQuery processing     var id = originalOptions.url+ JSON.stringify(originalOptions.data);      options.cache = false;      if (localCache.exist(id)) {         return {             send: function (headers, completeCallback) {                 completeCallback(200, "OK", localCache.get(id));             },             abort: function () {                 /* abort code, nothing needed here I guess... */             }         };     } });  $(function () {     var url = '/echo/jsonp/';     $('#ajaxButton').click(function (e) {         $.ajax({             url: url,             data: {                 test: 'value'             },             cache: true         }).done(function (data, status, jq) {             console.debug({                 data: data,                 status: status,                 jqXHR: jq             });         });     }); }); 

Fiddle HERE Some issues, our cache ID is dependent of the json2 lib JSON object representation.

Use Console view (F12) or FireBug to view some logs generated by the cache.

like image 146
TecHunter Avatar answered Sep 20 '22 12:09

TecHunter