3

検索関数に for ループがあり、ループ内でコールバックを実行するコールバックを実行する関数があり、ループの後、およびすべてのコールバックが完了した後に BUILD() 関数を実行したいと考えています。すべてのコールバックが完了する前にループが終了するため、その方法がわかりません。コールバックは、データを取得するための API リクエストであり、そのデータを使用して BUILD() したいと考えています。

deferred について調べたので、for ループを関数内に deferred に配置してから、'.then( ... )' で BUILD() を呼び出してみました。しかし、それはうまくいかないようです-私はそれを間違って理解していると思います。

ヘルプ?!

これは Google Maps Places API (search および getDetails) を使用していることに注意してください。

var types = {
    'gym' : 'fitness, gym',
    'grocery_or_supermarket': ''
}

function search() {
    for (var key in types) {
         var request = { ... };
         service.search(request, searchCallback);
    }
    // PROBLEM AREA
    BUILD();
}

function searchCallback(results, status) {
    for (var i = 0; i < results.length; i++) {
        var request = { ... };
        service.getDetails(request, detailsCallback);
    }
}

function detailsCallback(place, status) {
    // add place marker to maps and assign info window and info window event
}
4

2 に答える 2

3

コードを少し変更するだけで実現できます。

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 個の新しいローカル スコープが作成されます。スコープ内では、宣言された変数は親スコープからは見えません。親スコープの変数は、同じ名前の変数を宣言しない限り、「子」スコープの変数によって読み取りおよび更新できます。この機能は、私の回答の機能で使用されています。

于 2012-06-30T17:17:44.660 に答える
0

これはもう理解していると思いますが、以前のコールバック関数がまだ実行されている間に BUILD() が線形に呼び出されているためです。余分なスレッドを作成したようなものです。この問題を解決する 1 つの方法は、BUILD を for ループを含む検索関数からのコールバックにすることです。これにより、呼び出す前にすべての機能が完了することが保証されます。

この質問は、コールバックの実装に役立つ場合があります: JavaScript でカスタム コールバックを作成する

于 2012-06-30T17:19:12.823 に答える