Why you are facing this problem ?
To understand the root of the problem, you need to understand the concept of call-stack and async execution in javascript. Here i am giving you a brief introduction but enough to understand your problem
async execution in javascript happens outside of the current call stack. You are calling a function called loadJson which accepts a callback and the callback is executed inside an async handler called onreadystatechange. The status of the call stack in different stage of the execution has been illustrated below :
First, call stack is empty.
call stack
- - async handler
- - -------------
- - -empty-
- -
- - - - - -
Then loadjson is called and it's pushed into the call stack.
call stack
- - async handler
- - -------------
- - -empty-
- -
- loadJson-
- - - - - -
loadjosn executes XMLHttpRequest which is an async code.Async code executes outside of the call stack, somewhere we may call it async-handler here, and it waits there until the async execution is finished. At this point the loadjson function is done with and pushed out of the call stack.So after this call stack is empty again.
call stack
- - async handler
- - -------------
- empty - xhrHttpRequest ( wait until ajax finish fetching data )
- -
- - - - - -
When the async xmlhttprequest finished fetching data. the callback function is pushed into the callstack.
call stack
- - async handler
- - -------------
- - empty ( async execution finished execution)
-callback -
- - - - - -
By this time the callback function forgets that it was a callback for the laodJson function, because it's not called from inside loadjosn function rather it's called from a async handler. So the callback function executes like a separate , standalone function.It may appear from the code that the callback is called from loadjson , but at this point callback has no ties with loadjson function. it a result of an async execution.So invocation of callback has no ties with loadjson anymore.
that's why you can not return any result from callback or loadjosn that will populate the global variable mydata.
How you can solve it ?
you can follow many ways. You can use the old-school continuation-passing-style
, or you can use new es6 features like Promises
and async
-await
. They way you are doing it is called is continuation passing style. I assume you are already familiar with this style , so here i only providing the promise and async-await style for your convinience.
Promise way :
var mydata ;
loadJSON( (response) => {
// Parse JSON string into object
var actual_JSON = JSON.parse(response);
console.log(actual_JSON);
return actual_JSON;
}).then(response =>{ mydata = response;console.log(mydata)})
function loadJSON(callback) {
return new Promise(function (resolve,reject){
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', './my-data.json', true);
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
resolve(callback(xobj.responseText));
}
};
xobj.send(null);
})
}
Async-Await procedure :
function loadJson(){
return new Promise(function(resolve,reject){
var xobj = new XMLHttpRequest()
xobj.onreadystatechange = function(){
if(xobj.readyState == 4 && xobj.status == 200){
resolve(xobj.response)
}
}
xobj.open('GET', './my-data.json', true);
xobj.send()
})
}
async function askForJson(){
var data = await loadJson()
return data
}
askForJson().then(data=>console.log(data))