Solace
Solace

Reputation: 2189

Setting value of variable within promise chain in Javascript

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

Answers (2)

Useless Code
Useless Code

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

brk
brk

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

Related Questions