web-dev-qa-db-ja.com

続行する前に複数の非同期呼び出しが完了するのを待機しています

したがって、jquery.getを介してロードし、ドロップダウンに値を入力するためのいくつかのリクエストを行うページがあります。

$(function() {
    LoadCategories($('#Category'));
    LoadPositions($('#Position'));
    LoadDepartments($('#Department'));

    LoadContact();
};

次に、LoadContact()を呼び出します。これは別の呼び出しを行い、それが返されると、フォーム上のすべてのフィールドに値が設定されます。問題は、多くの場合、ドロップダウンにすべてが入力されていないため、正しい値に設定できないことです。

私ができるようにする必要があるのは、他のメソッドが完了し、コールバックの実行が完了した後にのみLoadContactを実行させることです。

しかし、ドロップダウンポピュレーションコールバックの最後に多数のフラグを配置する必要はありません。それをチェックし、LoadContact()を呼び出す前に再帰的なsetTimeoutコールチェックを行う必要があります。

JQueryには、「これらすべてが完了したら、これを実行してください」と言うことができる何かがありますか?

詳細私はこれらの線に沿って何かを考えています

$().executeAfter(
    function () {   // When these are done
        LoadCategories($('#Category'));
        LoadPositions($('#Position'));
        LoadDepartments($('#Department'));
    },
    LoadContact // Do this
);

...メソッドの実行中に発生するajax呼び出しを追跡し、それらがすべて完了したらLoadContactを呼び出す必要があります。

その関数で作成されているajaxをインターセプトする方法を知っていれば、これを行うためにjQuery拡張機能を作成できます。

私の解決策

;(function($) {
    $.fn.executeAfter = function(methods, callback) {

        var stack = [];

        var trackAjaxSend = function(event, XMLHttpRequest, ajaxOptions) {
            var url = ajaxOptions.url;

            stack.Push(url);
        }

        var trackAjaxComplete = function(event, XMLHttpRequest, ajaxOptions) {
            var url = ajaxOptions.url;

            var index = jQuery.inArray(url, stack);

            if (index >= 0) {
                stack.splice(index, 1);
            }

            if (stack.length == 0) {
                callback();
                $this.unbind("ajaxComplete");
            }
        }

        var $this = $(this);

        $this.ajaxSend(trackAjaxSend)
        $this.ajaxComplete(trackAjaxComplete)

        methods();
        $this.unbind("ajaxSend");
    };
})(jQuery);

これは、メソッドの呼び出し中にajaxSendイベントにバインドし、呼び出されたURLのリストを保持します(ただし、より良い一意のIDが必要です)。その後、ajaxSendからアンバインドされるため、関心のあるリクエストのみが追跡されます。また、ajaxCompleteにバインドし、返されるアイテムをスタックから削除します。スタックがゼロに達すると、コールバックが実行され、ajaxCompleteイベントのバインドが解除されます。

55
CaffGeek

次のように .ajaxStop() を使用できます。

_$(function() {
  $(document).ajaxStop(function() {
    $(this).unbind("ajaxStop"); //prevent running again when other calls finish
    LoadContact();
  });
  LoadCategories($('#Category'));
  LoadPositions($('#Position'));
  LoadDepartments($('#Department'));
});
_

これは、現在のすべてのリクエストが終了したときに実行され、それ自体のバインドを解除するため、ページ内の今後のajax呼び出しが実行されても実行されません。また、必ずajax呼び出しの前に配置し、十分早くバインドされるようにしてください。 .ajaxStart() でより重要ですが、両方で行うのがベストプラクティスです。

43
Nick Craver

Tom Lianzaの答え$.when() を展開すると、.ajaxStop()を使用するよりもはるかに優れた方法です。

唯一の注意点は、待機する必要がある非同期メソッドが Deferred object 。幸いなことに、jQuery ajax呼び出しは既にデフォルトでこれを行っています。したがって、質問からシナリオを実装するには、待機する必要があるメソッドは次のようになります。

function LoadCategories(argument){
    var deferred = $.ajax({
       // ajax setup
    }).then(function(response){ 
       // optional callback to handle this response 
    });
    return deferred;
}

次に、3つすべてのajax呼び出しが返され、オプションで独自のコールバックを実行した後にLoadContact()を呼び出します。

// setting variables to emphasize that the functions must return deferred objects
var deferred1 = LoadCategories($('#Category'));
var deferred2 = LoadPositions($('#Position'));
var deferred3 = LoadDepartments($('#Department'));

$.when(deferred1, deferred2, deferred3).then(LoadContact);
17
KPD

Jquery 1.5以降を使用している場合、Deferredオブジェクトが最善の策であると思われます。 http://api.jquery.com/category/deferred-object/

ヘルパーメソッドも、非常にいいです: http://api.jquery.com/jQuery.when/

7
Tom Lianza

ただし、ドロップダウンポピュレーションコールバックの最後に多数のフラグを配置する必要はありません。チェックして、LoadContact()を呼び出す前に再帰的なsetTimeoutコールチェックを行う必要があります。 ;
setTimeoutの必要はありません。各コールバックで、3つすべてのリストが読み込まれていることを確認し(またはカウンターを設定し、各コールバックで増やして、3になるまで待ちます)、コールバックからLoadContactを呼び出します。私にはとても簡単に思えます。

ajaxStopアプローチはうまくいくかもしれませんが、私はそれにあまり詳しくありません。

0
Nikita Rybak