简体   繁体   English

(仍然)对javascript闭包,ajax和返回值更加困惑

[英](still) more confusion over javascript closures, ajax, and return values

I'm trying to use JQuery .get() method and a javascript for loop to process some data from an external file. 我正在尝试使用JQuery .get()方法和javascript for循环来处理来自外部文件的某些数据。 I've read about closures and return values from callbacks on stackoverflow for a couple hours, and i'm still confused why this isn't working. 我已经阅读了两个小时的关于stackoverflow上的闭包和从回调返回值的信息,但我仍然感到困惑,为什么它不起作用。

Are the variables headers and countryData not global in scope with respect to the inner callback function? 就内部回调函数而言,变量标头countryData是否在范围上不是全局的? They are being assigned values as intended within the callback function, but then how do i access them once that is complete? 它们已在回调函数中按预期分配值,但是一旦完成,如何访问它们? And possibly an example wihtout using the alert() function? 还有可能使用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' ...!?
}   

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. $ .get()连接到服务器,并在服务器返回答案时运行其回调函数。 But $.get() completes once the request is sent , not when the response is returned. 但是$ .get()是在发送请求后完成的,而不是在返回响应时完成的。 So your last two console.log() lines are running before the callback function is executed. 因此,最后两个console.log()行在执行回调函数之前正在运行。

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. 一旦执行了回调函数,就只能访问headerscountryData变量,并且您知道发生的唯一地方是在回调函数本身内部。 or other code that it calls. 或它调用的其他代码。

$.get is asynchronous , meaning the rest of the script will not wait for it to complete. $.get异步的 ,这意味着脚本的其余部分将不等待它完成。 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). 如果您需要比成功回调提供的更多控制权,则可以使用jQuery.Deferred类( docs )减轻此jQuery.Deferred ,或者可以使调用同步 (这意味着脚本的其余部分在执行之前等待完成) 。

Synchronous AJAX Calls 同步AJAX呼叫

You'll need to use $.ajax ( docs ), just pass-in async:false : 您需要使用$.ajaxdocs ),只需传入async:false

$.ajax({
  url: inCSV,
  async: false,
  success: function() { /* ... */ }
});

// code here will not execute until the ajax call above is complete

Deferred Objects 延期对象

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
});

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: 步骤1.使用以下代码声明状态变量:

var headers;  
var countryData = [];

Step 2. You call the server with this code 步骤2.使用此代码调用服务器

$.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 步骤3.您将状态变量与此代码一起使用

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: 步骤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", ..'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM