0

I'm using the code from http://www.kryptonite-dove.com/blog/load-json-file-locally-using-pure-javascript to read a json file and store it as a variable.

The code works fine; my json objects prints to the console successfully. However, I wish to access the variable outside the function. I moved the definition outside, but that does not work. What am I doing wrong?

function loadJSON(callback) {   
    var xobj = new XMLHttpRequest();
    xobj.overrideMimeType("application/json");
    xobj.open('GET', 'my_data.json', true); // Replace 'my_data' with the path to your file
    xobj.onreadystatechange = function () {
      if (xobj.readyState == 4 && xobj.status == "200") {
        // Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode
        callback(xobj.responseText);
      }
  };
  xobj.send(null);  
}


var actual_JSON; <--- I moved the definition outside here 
function init() {
  loadJSON(function(response) {
  // Parse JSON string into object
    actual_JSON = JSON.parse(response);  
    console.log(actual_JSON); ---> this works
 });
}
init();
console.log(actual_JSON);     ----> this doesn't work; I get the var is undefined 
pomegranate
  • 755
  • 5
  • 19
  • `loadJSON` is async, the console log on the last line runs before load completes. – georg Jan 26 '15 at 04:40
  • @Steve whoops, sorry, I forgot to add the call in. fixing now – pomegranate Jan 26 '15 at 04:42
  • @georg any suggestions for how can I ensure I can always access whatever is in actual_JSON then? – pomegranate Jan 26 '15 at 04:44
  • @pomegranate: you can only access it in the `load` callback, or functions you're calling from there. Thus, it doesn't make sense to make it global. See http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call for more details and explanations. – georg Jan 26 '15 at 04:46
  • You can't treat an asynchronous result like synchronous code. You have to write code that works asynchronously by processing the result inside the completion function or using callbacks to call some other function. See this answer for a description of your options: http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call/16825593#16825593. The async completion happens sometime LATER which means code right after your function runs BEFORE the result is available. – jfriend00 Jan 26 '15 at 04:50
  • Probably could be marked a dup of: http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call/16825593#16825593 since all the solutions are described there. – jfriend00 Jan 26 '15 at 04:50
  • @jfriend00: I thought about that, but since he doesn't "return" anything, that's technically not a dupe, although essentially the same question. – georg Jan 26 '15 at 04:52
  • @georg - he's trying to use the ajax result in code right after the ajax call is initiated which is pretty much the same issue. As you say, the solutions are entirely the same and part of the reason for "dup" is to avoid duplicating the exact same answers over and over even if the question is asked slightly differently. I didn't myself yet mark it as a dup - still thinking about it. – jfriend00 Jan 26 '15 at 04:53

2 Answers2

1

loadJSON makes a GET request. The callback function that you are sending to it, gets executed when the response comes back, i.e when the JSON is fetched.

init();
console.log(actual_JSON);

So, init() gets called and it internally does a GET request, and since this is async it does not block the execution of the rest of the code. So the next line console.log(actual_JSON) get executed, at this point the value of actual_JSON is not modified.

You can do something like this to make it a little more clear:

function init() {
    loadJSON(function(response) {
        actual_JSON = JSON.parse(response);  
        consumeData(actual_JSON); //call another function with the actual JSON
    });
}

function consumeData(actualJson) {
    //write the rest of the code here
}
surajck
  • 1,186
  • 9
  • 23
0

Look inside your loadJSON you see it takes a function as a callback. This is done because a HTTP request is being sent off asynchronously and it's up to the server and network to determine how long it takes to run, meanwhile the rest of JavaScript on your page continues to execute (e.g., your final console.log) before the variable is set.

When the HTTP request is finished (the onreadystatechange bit), it'll run the function you passed in to loadJSON — that's the function where you're setting the variable and your console.log that works.

You how a few options:

  1. Run your Ajax synchronously so it doesn't execute the rest of the JS (bad idea)
  2. Add a callback to what you're doing:

    var actual_JSON; <--- I moved the definition outside here 
    function init() {
      loadJSON(function(response) {
      // Parse JSON string into object
        actual_JSON = JSON.parse(response);
        exec_after_init();
     });
    
    }
    
    init();
    
    function exec_after_init {
       console.log(actual_JSON);
    } 
    

Note: code above has not been tested

vol7ron
  • 40,809
  • 21
  • 119
  • 172