我正在尝试使用JQuery .get()方法和javascript for循环来处理来自外部文件的一些数据。我已经阅读了关于stackoverflow上的回调的闭包和返回值几个小时,我仍然感到困惑,为什么这不起作用。
关于内部回调函数,变量 headers 和 countryData 的范围是否全局?它们在回调函数中按预期分配值,但是一旦完成,我该如何访问它们?可能是一个没有使用alert()函数的例子?
function processData(inCSV){
var headers;
var countryData = [];
$.get(inCSV, function(data) {
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", ..'
});
console.log('outside',headers); // output 'outside undefined' ...!?
console.log('inside',countryData['Brazil']); // output 'outside undefined' ...!?
}
答案 0 :(得分:3)
问题不在于闭包,问题在于异步功能。 $ .get()连接到服务器,并在服务器返回答案时运行其回调函数。但是,一旦请求发送,$ .get()就会完成,而不是在返回响应时。因此,在执行回调函数之前,最后两个console.log()行正在运行。
一旦执行了回调函数,您只能访问headers
和countryData
变量,并且您知道发生的唯一位置是回调函数本身。或者它调用的其他代码。
答案 1 :(得分:0)
$.get
是异步,这意味着脚本的其余部分不会等待它完成。如果您需要比成功回调提供的控制更多的控制,您可以使用jQuery.Deferred
类(docs)来缓解此问题,或者您可以进行同步调用(意味着脚本的其余部分等待它在执行之前完成。)
您需要使用$.ajax
(docs),只需传入async:false
:
$.ajax({
url: inCSV,
async: false,
success: function() { /* ... */ }
});
// code here will not execute until the ajax call above is complete
function processData(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
});
答案 2 :(得分:0)
这不是封闭问题。只是代码行没有按照它们的编写顺序执行。
这是一个基本的事件编程问题:进程的结束位于代码的中间。一旦你意识到这一点,这不是一个大问题。您只需在正确的位置写下流程的结尾。
在您的情况下,事情按此顺序发生:
步骤1.使用以下代码声明状态变量:
var headers;
var countryData = [];
步骤2.使用此代码调用服务器
$.get(inCSV, <CALLBACK>)
此时回调中的内容根本不重要。在服务器响应返回之前,它不会被执行。
步骤3.您将状态变量与此代码一起使用
console.log('outside',headers); // output 'outside undefined' ...!?
console.log('inside',countryData['Brazil']); // output 'outside undefined' ...!?
它们是未定义的,这是完全可以预期的,因为没有代码初始化它们。
步骤4.响应从服务器返回:
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", ..'