0

我正在尝试使用 JQuery .get() 方法和 javascript for 循环来处理来自外部文件的一些数据。我已经阅读了几个小时关于 stackoverflow 回调的闭包和返回值,但我仍然很困惑为什么这不起作用。

对于内部回调函数,变量headerscountryData在范围内不是全局的吗?在回调函数中为它们分配了预期的值,但是一旦完成,我如何访问它们?并且可能是一个不使用 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' ...!?
}   
4

3 回答 3

3

问题不在于闭包,问题在于异步函数。$.get() 连接到服务器,并在服务器返回答案时运行其回调函数。但是 $.get() 在发送请求后完成,而不是在返回响应时完成。所以你的最后两行 console.log() 在回调函数执行之前运行。

回调函数执行后,您只能访问headerscountryData变量,并且您知道发生的唯一地方是回调函数本身。或它调用的其他代码。

于 2012-06-28T16:06:03.523 回答
0

$.get异步的,这意味着脚本的其余部分不会等待它完成。如果您需要比成功回调提供的更多控制,您可以使用jQuery.Deferred类 ( docs ) 来缓解这种情况,或者您可以使调用同步(这意味着脚本的其余部分在执行之前等待它完成)。

同步 AJAX 调用

您需要使用$.ajaxdocs),只需传入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
});
于 2012-06-28T16:16:25.283 回答
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", ..'
于 2012-06-28T16:17:02.270 回答