コードを少し変更するだけで実現できます。
var total = 1337; // Some number
var internal_counter = 0;
var fn_callback = function() {
searchCallback.apply(this, arguments);
if (++internal_counter === total) {
BUILD();
}
};
for (var i=0; i<total; i++) {
service.search(request, fn_callback);
...
説明
まず、ローカル関数と変数を作成します。
- 変数はカウンターで、コールバックが呼び出されると増加します。
service.search
関数は、元のコールバックを呼び出す非同期メソッド ( ) に渡されます。カウンターを増やした後、合計反復回数を保持する変数に対してカウンターの値を確認します。これらが等しい場合は、仕上げ関数 ( BUILD
) を呼び出します。
複雑なケース: ネストされたコールバックの処理。
var types = { '...' : ' ... ' };
function search() {
var keys = Object.keys(types);
var total = keys.length;
// This counter keeps track of the number of completely finished callbacks
// (search_callback has run AND all of its details_callbacks has run)
var internal_counter = 0;
for (var i=0; i<total; i++) {
var request = { '...' : ' ... ' };
services.search(request, fn_searchCallback);
}
// LOCAL Function declaration (which references `internal_counter`)
function fn_searchCallback(results, status) {
// Create a local counter for the callbacks
// I'm showing another way of using a counter: The opposite way
// Instead of counting the # of finished callbacks, count the number
// of *pending* processes. When this counter reaches zero, we're done.
var local_counter = results.length;
for (var i=0; i<results.length; i++) {
service.getDetails(request, fn_detailsCallback);
}
// Another LOCAL function (which references `local_counter`)
function fn_detailsCallback(result, status) {
// Run the function logic of detailsCallback (from the question)
// " ... add place marker to maps and assign info window ... "
// Reduce the counter of pending detailsCallback calls.
// If it's zero, all detailsCallbacks has run.
if (--local_counter === 0) {
// Increase the "completely finished" counter
// and check if we're finished.
if (++internal_counter === total) {
BUILD();
}
}
} // end of fn_detailsCallback
} // end of fn_searchCallback
}
関数ロジックはコメントで説明されています。関数はネストされたローカル関数と変数を使用するため、このセクションの見出しに「Complex」というプレフィックスを付けました。視覚的な説明:
var types, BUILD;
function search
var keys, total, internal_counter, fn_searchCallback;
function fn_searchCallback
var result, status; // Declared in the formal arguments
var local_counter, i, fn_detailsCallback;
function fn_detailsCallback
var result, status; // Declared in the formal arguments
前の図では、各インデント レベルはMDNの新しいスコープの説明を意味します。
関数がたとえば 42 回呼び出されると、同じ親スコープを共有する 42 個の新しいローカル スコープが作成されます。スコープ内では、宣言された変数は親スコープからは見えません。親スコープの変数は、同じ名前の変数を宣言しない限り、「子」スコープの変数によって読み取りおよび更新できます。この機能は、私の回答の機能で使用されています。