0

JQuery .get() メソッドと javascript for ループを使用して、外部ファイルからのデータを処理しようとしています。スタックオーバーフローのコールバックからのクロージャーと戻り値について数時間読んだことがありますが、なぜこれが機能しないのかまだ混乱しています。

変数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()は、応答が返されたときではなく、要求が送信されると完了します。したがって、最後の 2 つの console.log() 行は、コールバック関数が実行される前に実行されています。

headersコールバック関数が実行されると、 変数と変数にのみアクセスできますcountryData。発生したことがわかっている唯一の場所は、コールバック関数自体の内部です。またはそれが呼び出す他のコード。

于 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 に答える