2016-09-02 9 views
1

私はアイテムの行を持っています。各行には異なる数の項目があります。 ロードしたアイテムの合計数を記録するカウンタが必要です。あなたは、成功時に、各ロード機能を見ることができるように私はこの(私が問題に関連していないものをコメントアウトしている)再帰的なAJAX呼び出しの中にカウンタを保持するには?

$(document).ready(function() { 
    var num_loaded = 0; 
    var row = 0; 
    load(row, num_loaded); 
} 

function load(row, num_loaded) { 
    var count = num_loaded; 
    $.ajax({ 

     // url and other stuff 
     // ... 

     success: function (response) { 
      for (i = 0; i < response.items.length; i++) { 

       // load item[i] 
       // ... 

       count++; 
      } 

      // logic that checks row+1 is not out of bounds 
      // ... 

      load(row+1, count); 
     } 
    }) 

    console.log(count); 
} 

のように、AJAX呼び出しを介して、再帰的にすべての行をループ機能を持っていますカウントを追跡するパラメータを渡します。これは動作せず、NaNを取得し続けるか、コンソールで未定義です。どのようにこれを達成し、ロードされるアイテムの数の最終的なカウントだけを見ますか?

+0

count'と '' num_loaded'の違いは何ですか? – nem035

+0

@ nem035 no difference –

+0

ok、私はあなたにいくつかの例を教えてくれました。うまくいけば助かります – nem035

答えて

0

あなたの主な問題は、同期コールのようにajaxを処理していることが実際には非同期であるという点で、コールバックを持つものとかなり共通しています。つまり、ajaxの呼び出しの直後にcountを印刷しようとしていますが、その時点ではcountは更新されません。ここで

var count = num_loaded; 
$.ajax({ 
    // ... this updates count some time later 
}); 
// this happens right after we call $.ajax but before the success callback 
// so count still has the same value as before we called $.ajax 
console.log(count); 

あなたはまた、あなたはそれが各関数呼び出しの呼び出しスタックに再作成されることを意味load()方法、内部のあなたのカウンターを定義している

を見てとることができrelated questionです。

あなたは非同期コールバックを再帰的にcountを渡すと、あなたの再帰が停止したときに、それが正しい値を持つことになります(つまり、最大の行のベースケースに到達した)ので、あなたは、コールバックの内側にそれを印刷する必要があります。

$(document).ready(function() { 
    load(0, 0); 
} 

function load(row, count) { 
    $.ajax({ 
     // ...  
     success: function(response) { 

     // ... loop that increments the count 

     if (/* your base case is reached */) { 
      console.log(count); 
     } else { 
      load(row + 1, count); 
     } 
     } 
    }); 
    } 
} 

よりクリーンでより合理的なアプローチは、約束を使用することです。あなたはload()方法が成功した場合にPromise意志を返すことができ、次のいずれかの次の行をロードする約束に

  • 決意、またはベースケースに達した場合
  • 印刷count

約束はチェーン可能なので、我々はまた、簡単に再帰的にcountを渡すことができます。

function loadWithPromise(row, count) { 
    return new Promise(function(resolve) { 
    $.ajax({ 
     // ...  
     success: function(response) { 

     // ... loop that increments the count 

     // if we reached the base case, resolve this promise (and thus the whole chain) 
     if (/* your base case is reached */) { 
      resolve(count); 
     } 
     // otherwise load the next promise 
     else { 
      resolve(loadWithPromise(row + 1, count)); 
     } 
     } 
    }); 
    }); 
} 

// recursively load all rows and then print count once we're done 
loadWithPromise(0, 0).then(function(count) { 
    console.log(count); 
}); 

行を順次ロードする必要がない場合は、あなたがload()へのへのすべての呼び出しを待つためにPromise.allを使用することができますcountを印刷する前に終了してください。こうすることで、すべての約束事を配列に保持し、それらを独立に起こさせることができます。また、再帰は必要ありません。欠点は、しかし、これらの約束は今無関係になるので、あなたはcountがグローバルに定義されている必要がありますということです。

var count = 0; 

function loadWithPromise(row) { 
    return new Promise(function(resolve) { 
    $.ajax({ 
     // ...  
     success: function(response) { 

     // ... loop that increments the count 

     resolve(); 
     } 
    }); 
    }); 
} 

var promises = []; 
for (var row = 0; row < MAX_ROWS; row++) { 
    promises.push(loadWithPromise(row)); 
} 

// once all loading operations have resolved, print the count 
Promise.all(promises).then(function() { 
    console.log(count); 
}); 
+0

ロードの外側スコープでカウンタを起動すると、すべての機能の外にあることを意味するのでしょうか? –

+0

これはまた、グローバル変数としてカウンタを設定していることを意味します。メモリリークの問題を引き起こしませんか? –

+0

何かをグローバルにしたくない場合は、[IIFE]でラップしてください(http://stackoverflow.com/documentation/javascript/4655/modularization-techniques/16340/immediately-invoked-function-expressions-iife #t = 201609020345127395816)。メモリリークに関しては、これは数字のような原始的なデータの問題ではありません。たとえば、DOMノード参照をグローバルに格納していて、クロージャを介していくつかの関数にアクセスできるようにすると、ガベージコレクションが適切に行われない可能性がありますが、実際にこのような心配はありません。 – nem035

関連する問題