Quick Description of what my JS app should do...
I am using the JavaScript Promise library RSVP.js - https://github.com/tildeio/rsvp.js/ in my project.
Some things the code does...
- Load 4-5 JOSN URLs using AJAX on 1st request and all followup requests will instead serve JSON from a cached variable.
- JavaScript Promise() is used to load all JSON data before executing other code in the app.
- Global variable window.jsonCache will hold the cached JSON and Promise() after they are loaded there first time with the AJAX request.
- getJSON(jsonUrl, key) is a function that returns a Promise() and also makes an AJAX request or serves cached window.jsonCache[key-name-here] data if available.
The goal is to use JavaScript's Promise()
and to also cache the JSON data returned from each AJAX request and serve the cached version on any repeat calls for the data instead of making duplicate AJAX requests each time a script on the page calls for the data.
I have started work on a demo using the best of my JavaScript knowledge which I am still learning new JS daily. I am much stronger in PHP but progressing in JS.
The Problem where I need assistance/help
I believe I have it mostly working and almost to my needs. My problem is on my JSFiddle demo http://jsfiddle.net/jasondavis/nzzh1hee/5/ which runs all the code explained below. The demo loads my JSON data with an AJAX request for all 4 of my JSON URLs. It should then cache the result for future calls to this data to be served from. It is instead making repeat AJAX calls the next time I call/run the code.
So somewhere it seems my caching mechanism is not working correctly or possibbly some other issue even.
The final result should run my Promise()
code regardless if the JSON data is served from an AJAX request or from a cached variable.
I need help to get this part of the flow working please. The JSFiddle above has a working demo of this code which you can view the Dev tools console to see my debug data.
UPDATE
SO User Kevin B identified my problem source being that my 2nd call to the data is called before my 1st call has time to cache the values which is why repeat AJAX calls are being made!
I could use some help in modifying this existing code to get around this issue and as mentioned by user Jared Smith if I could Memoize the AJAX function getJSON(jsonUrl, key) would be a good method but I basically though that is what I had done so I could use some help here please!
Side note...
The JSFiddle demo uses /echo/json/
as the endpoints for all the AJAX request which return no data in the demo. So I have also tested locally loading real JSON data from my AJAX request just to make sure that was not the source of my issue and it did not make a difference.
All code and text below this line is just a breakdown of my code explained better. The text above is enough to understand the problem and goal and the JSFiddle demo runs the code below
So I will briefly try to break down my demo code below to explain some key parts of it...
jsonCache will hold the cached JSON data after a successful AJAX load of it for future calls to the JSON data to be served from this cache instead of making a new AJAX request.
// Global variable to hold cached JSON data retrieved from AJAX requests
window.jsonCache = {
users: '',
milestones: '',
tags: '',
task: ''
};
getJSON(jsonUrl, key) is a function that returns a Promise() and also make an AJAX request or serves cached data if available. The jsonUrl is the URL to the JSON data on server and the key is a name assigned to access the cached data later on.
AJAX request to get JSON data and populate cache variables
I then use if(isEmpty(window.jsonCache[key])) { }
to make the AJAX request if the data is not previously cached.
The AJAX request will call a handler()
callback function on success which in turn also calls the Promise() resolve(this.response) function
passing the JSON data into the resolve function. On AJAX failure it will call the Promise() Reject() function
.
In the }else{
statement it will simply return the cached version of the data by accessing it with its key
value and will not make a duplicate AJAX request for this particular key
of data/url.
JSFiddle Demo using the code from below http://jsfiddle.net/jasondavis/nzzh1hee/5/
Utility Functions Used in code below
// RSVP.js Promise Library used from https://github.com/tildeio/rsvp.js/
// utility function to check for empty variables
function isEmpty(str) {
return (!str || 0 === str.length || str === '');
}
// Global variable to hold cached JSON data retrieved from AJAX requests
window.jsonCache = {
users: '',
milestones: '',
tags: '',
task: ''
};
PROMISE() FUNCTION TO MAKE AJAX REQUEST FOR JSON DATA
// AJAX function to load JSON data using Promise()
var getJSON = function(url, key) {
var promise = new RSVP.Promise(function(resolve, reject){
// If cached data is not set then make AJAX requiest to get it
if(isEmpty(window.jsonCache[key])) {
var client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
console.log('---- "client" XMLHttpRequest/AJAX variable ======= ',client);
////////////// temp test
// jsonCache[key] = ' AJAX Response';
////////////// end temp test
function handler() {
if (this.readyState === this.DONE) {
// On AJAX success, resolve() our Promise() and set result to cached variable
// to avoid duplicate AJAX requests for this jsonCache[key] Data where "key"
// is used to assign to each AJAX endpoint URL/request of JSON data...
// (milestones, tasks, users, etc...)
if (this.status === 200) {
window.jsonCache[key] = this.response;
window.jsonCache[key] = key+' AJAX Response';
console.log('---- window.jsonCache['+key+'] ====== ',window.jsonCache[key]);
// Resolve() the Promise() on AJAX success
resolve(this.response);
// On AJAX failure, reject() our Promise()
}else{
reject(this);
}
}
};
// If JSON data for this key is already cached, then return the cached version
// instead of making a new AJAX request!
}else{
console.log('---- window.jsonCache['+key+'] ====== ',window.jsonCache[key]);
// Return cached version of JSON data as a Promise() and pass into the
// Resolve() function
window.jsonCache[key] = key+' CACHED Response';
resolve(window.jsonCache[key]);
}
});
return promise;
};
EXAMPLE USAGE DEMO USING THE CODE FROM ABOVE
First call/load of JSON data which loads through AJAX request and caches results to variables.
// EXAMPLE USAGE DEMO
// usage loading multiple AJAX calls using Promises
// Each of these 4 JSON URLs below will be loaded using Promise() and AJAX requests on
// first call to them. 2nd call to them should instead serve a cached version stored in
// a global variable window.jsonCache.KEYNAME-HERE
var promises = {
users: getJSON('/echo/json/', 'users'),
milestones: getJSON('/echo/json/', 'milestones'),
tags: getJSON('/echo/json/', 'tags'),
task: getJSON('/echo/json/', 'task')
};
// Load the AJAX JSON function above for each Promise()
// Handles success, finally() for every load, and error for when error occurs
RSVP.hash(promises).then(function(results) {
console.log(results);
console.log(results.users); // print the users JSON results
}).finally(function(){
console.log('finally() function ran on success and failure.... It is always ran!');
}).catch(function(reason){
console.log('[ERROR] REASON:',reason.statusText); //if any of the promises fails.
});
2nd call to load JSON data which should load from cached variable but is still loading from a new AJAX requests
/////////////////////////////////////////////////////////////////////////////////////////////////
//
//
// Below is another call to load the same 4 JSON data to test and see if it is
// served from a cached variable instead of making a duplicate 2nd AJAX request for each item.
//
//
////////////////////////////////////////////////////////////////////////////////////////////////
// EXAMPLE USAGE DEMO
// usage loading multiple AJAX calls using Promises
// Each of these 4 JSON URLs below will be loaded using Promise() and AJAX requests on
// first call to them. 2nd call to them should instead serve a cached version stored in
// a global variable window.jsonCache.KEYNAME-HERE
var promises = {
users: getJSON('/echo/json/', 'users'),
milestones: getJSON('/echo/json/', 'milestones'),
tags: getJSON('/echo/json/', 'tags'),
task: getJSON('/echo/json/', 'task')
};
// Load the AJAX JSON function above for each Promise()
// Handles success, finally() for every load, and error for when error occurs
RSVP.hash(promises).then(function(results) {
console.log(results);
console.log(results.users); // print the users JSON results
}).finally(function(){
console.log('finally() function ran on success and failure.... It is always ran!');
}).catch(function(reason){
console.log('[ERROR] REASON:',reason.statusText); //if any of the promises fails.
});