Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
109
rated 0 times [  112] [ 3]  / answers: 1 / hits: 168815  / 11 Years ago, fri, june 14, 2013, 12:00:00

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.


More From » jquery

 Answers
19

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.


[#77626] Wednesday, June 12, 2013, 11 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
gerardob

Total Points: 571
Total Questions: 115
Total Answers: 96

Location: Cyprus
Member since Mon, Oct 24, 2022
2 Years ago
;