Reputation: 2189
In my web application, there are several components that will need access to the same data (in JSON). To avoid making unnecessary REST calls, I made a module that is supposed make a fetch request and store the result in a variable. On subsequent requests... if the data is available in the module, it will be directly returned (so only one network request is necessary).
For example:
var data_module = function(){
var data; //Module stores the json data in a variable
return{ //Returns an object that contains a public method accessible to external functions
get_json:function(){
if(data){ //If data already exists, then return a Promise object that immediately resolves with data
return Promise.resolve(data);
}
else{ //Else if data does not exist, make fetch request
fetch('/rest/url/endpoint', {credentials:'include'})
.then(function(response){
if(!response.ok){
throw new Error(response.statusText);
}
return response.json(); //Returns json of response
})
.then(function(json){
data = json; //Assigns data the value of json to store the result for subsequent requests
return Promise.resolve(data) //Returns a Promise that resolves with data
});
}
} //Public method that is supposed to provide access to data
}
}(); //Module will automatically execute
Outside of the module, I will try to access data like so:
some_dom_element.onclick = function(){ //Some html element is clicked and we need the data
data_module.get_json().then(function(json){
console.log(json); //However this never gets called
});
}
It does not work. Even though data_module's get_json function returns a Promise, the .then method does not get called outside of data_module. I was wondering if anyone can explain why this happens? (Or provide a general direction of how to modify the solution to achieve the goal of storing json results of fetch requests).
Thanks in advance!
Upvotes: 1
Views: 170
Reputation: 12402
You could actually make the code a little shorter by storing the promise that response.json()
returns and just returning it rather than storing the text and generating a new Promise every time you get it from the cache.
let data_module = (function() {
let data;
return {
get_json: () => {
if (!data) {
data = fetch('https://jsonplaceholder.typicode.com/posts/1', {
credentials: 'include'
})
.then(response => {
if (!response.ok) {
// clear data so next time it tries to contact the server again
data = undefined;
throw new Error(`${response.status}: ${response.statusText}`);
} else {
// return the promise that .json() returns so it is stored
// in data
return response.json();
}
});
}
return data;
}
};
}());
data_module.get_json().then(data => {
console.log(data);
});
data_module.get_json().then(data => {
console.log(data);
});
I used let
and arrow functions =>
since any browser that supports fetch
also supports those.
Upvotes: 1
Reputation: 50291
You need to return the fetch
var data_module = (function() {
var data; //Module stores the json data in a variable
return { //Returns an object that contains a public method accessible to external functions
get_json: function() {
if (data) { //If data already exists, then return a Promise object that immediately resolves with data
console.log("** From CACHE **")
return Promise.resolve(data);
} else { //Else if data does not exist, make fetch request
// returning the fetch
return fetch('https://jsonplaceholder.typicode.com/posts/1', {
credentials: 'include'
})
.then(function(response) {
if (!response.ok) {
throw new Error(response.statusText);
}
return response.json(); //Returns json of response
})
.then(function(json) {
data = json;
return Promise.resolve(data) //Returns a Promise that resolves with data
});
}
} //Public method that is supposed to provide access to data
}
}()); //Module will automatically execute
//Outside of the module, I will try to access data like so:
var some_dom_element = document.getElementById("testBt")
some_dom_element.onclick = function() { //Some html element is clicked and we need the data
data_module.get_json().then(function(json) {
console.log(json); //However this never gets called
});
}
<button id="testBt">Test</button>
Upvotes: 2