(still) More Confusion Over Javascript Closures, Ajax, And Return Values
Solution 1:
The problem isn't the closure, the problem is asynchronous functions. $.get() connects to a server, and runs its callback function when the server returns an answer. But $.get() completes once the request is sent, not when the response is returned. So your last two console.log() lines are running before the callback function is executed.
You can only access the headers
and countryData
variables once the callback function has executed, and the only place you know that has happened is inside the callback function itself. or other code that it calls.
Solution 2:
It's not a closure problem. It's just that the code lines doesn't execute in the order they are written.
It's a basic event programming problem: the end of the process is in the middle of the code. It's not a big problem once you're aware of it. You just have to write the end of your process at the right place.
In your case, things happen in this order:
Step 1. State variables are declared with this code:
var headers;
var countryData = [];
Step 2. You call the server with this code
$.get(inCSV, <CALLBACK>)
At this point what's in the callback has no importance at all. It won't be executed until the server response comes back.
Step 3. You use the state variables with this code
console.log('outside',headers); // output'outside undefined' ...!?
console.log('inside',countryData['Brazil']); // output'outside undefined' ...!?
They are undefined, which is perfectly expectable because no code initialized them.
Step 4. Response comes back from the server:
var lines = data.split('\r\n');
for(var i=0;i<=lines.length-1;i++){
var lineData = lines[i].split(',');
if(i != 0){
countryData[lineData[1]] = lineData.slice(2,lineData.length);
} else {
headers = lineData.slice(2,lineData.length);
}
}
console.log('inside',headers); // output'inside ["1971", "1972", "1973" ...'
console.log('inside',countryData['Brazil']); // output'inside ["56.4", "54.6", ..'
Solution 3:
$.get
is asynchronous, meaning the rest of the script will not wait for it to complete. You can use the jQuery.Deferred
class (docs) to mitigate this if you need more control than is offered by the success callback, or you can make the call synchronous (meaning the rest of the script will wait for it to finish before executing).
Synchronous AJAX Calls
You'll need to use $.ajax
(docs), just pass-in async:false
:
$.ajax({
url: inCSV,
async: false,
success: function() { /* ... */ }
});
// code here will not execute until the ajax call above is complete
Deferred Objects
functionprocessData(inCSV) {
var deferred = jQuery.Deferred();
$.ajax({
url: inCSV,
success: function(data){
// do stuff
deferred.resolve([data]);
},
error: function() {
deferred.reject();
}
});
return deferred;
}
processingData = processData(inCSV);
// any code that doesn't care about the processing results can go here// code that relies on headers or countryData must go in a block like this// you can add as many "done" blocks as you like
processingData.done(function(data){
// mess with data here
});
Post a Comment for "(still) More Confusion Over Javascript Closures, Ajax, And Return Values"