33

ブラウザをロックせずに一連のNajaxリクエストを行う必要があり、これを実現するためにjquery遅延オブジェクトを使用したいと思います。

これは3つのリクエストを含む単純化された例ですが、私のプログラムは100を超えるキューを作成する必要がある場合があります(これは正確なユースケースではないことに注意してください。実際のコードは、次の実行前にステップ(N-1)の成功を確認する必要があります。ステップ):

$(document).ready(function(){

    var deferred = $.Deferred();

    var countries = ["US", "CA", "MX"];

    $.each(countries, function(index, country){

        deferred.pipe(getData(country));

    });

 });

function getData(country){

    var data = {
        "country": country  
    };


    console.log("Making request for [" + country + "]");

    return $.ajax({
        type: "POST",
        url: "ajax.jsp",
        data: data,
        dataType: "JSON",
        success: function(){
            console.log("Successful request for [" + country + "]");
        }
    });

}

コンソールに書き込まれる内容は次のとおりです(すべての要求は並行して行われ、応答時間は予想どおり各国のデータのサイズに正比例します。

Making request for [US]
Making request for [CA]
Making request for [MX]
Successful request for [MX]
Successful request for [CA]
Successful request for [US]

延期されたオブジェクトにこれらをキューに入れるにはどうすればよいですか?パイプに変更を加えてみましたが、同じ結果が得られます。

望ましい結果は次のとおりです。

Making request for [US]
Successful request for [US]
Making request for [CA]
Successful request for [CA]
Making request for [MX]
Successful request for [MX]

編集:

配列を使用してリクエストパラメータを保存するという提案に感謝しますが、jqueryの遅延オブジェクトにはリクエストをキューに入れる機能があり、この機能を最大限に活用する方法を学びたいと思っています。

これは事実上私がやろうとしていることです:

when(request[0]).pipe(request[1]).pipe(request[2])... pipe(request[N]);

ただし、各トラバーサルを効果的に使用するために、一度に1ステップずつパイプにリクエストを割り当てたいと思います。

deferred.pipe(request[0]);
deferred.pipe(request[1]);
deferred.pipe(request[2]);
4

6 に答える 6

31

カスタムオブジェクトを使用

function DeferredAjax(opts) {
    this.options=opts;
    this.deferred=$.Deferred();
    this.country=opts.country;
}
DeferredAjax.prototype.invoke=function() {
    var self=this, data={country:self.country};
    console.log("Making request for [" + self.country + "]");

    return $.ajax({
        type: "GET",
        url: "wait.php",
        data: data,
        dataType: "JSON",
        success: function(){
            console.log("Successful request for [" + self.country + "]");
            self.deferred.resolve();
        }
    });
};
DeferredAjax.prototype.promise=function() {
    return this.deferred.promise();
};


var countries = ["US", "CA", "MX"], startingpoint = $.Deferred();
startingpoint.resolve();

$.each(countries, function(ix, country) {
    var da = new DeferredAjax({
        country: country
    });
    $.when(startingpoint ).then(function() {
        da.invoke();
    });
    startingpoint= da;
});

フィドルhttp://jsfiddle.net/7kuX9/1/

もう少し明確にするために、最後の行を書くことができます

c1=new DeferredAjax( {country:"US"} );
c2=new DeferredAjax( {country:"CA"} );
c3=new DeferredAjax( {country:"MX"} );

$.when( c1 ).then( function() {c2.invoke();} );
$.when( c2 ).then( function() {c3.invoke();} );

パイプ付き

function fireRequest(country) {
        return $.ajax({
            type: "GET",
            url: "wait.php",
            data: {country:country},
            dataType: "JSON",
            success: function(){
                console.log("Successful request for [" + country + "]");
            }
        });
}

var countries=["US","CA","MX"], startingpoint=$.Deferred();
startingpoint.resolve();

$.each(countries,function(ix,country) {
    startingpoint=startingpoint.pipe( function() {
        console.log("Making request for [" + country + "]");
        return fireRequest(country);
    });
});

http://jsfiddle.net/k8aUj/1/

編集:結果ウィンドウにログを出力するフィドルhttp://jsfiddle.net/k8aUj/3/

各パイプ呼び出しは新しいpromiseを返し、それは次のパイプに使用されます。私はsccess関数のみを提供したことに注意してください。失敗に対しても、同様の関数を提供する必要があります。

各ソリューションでは、Ajax呼び出しは、関数でラップすることによって必要になるまで遅延され、チェーンを構築するためにリスト内の各アイテムに対して新しいPromiseが作成されます。

カスタムオブジェクトはチェーンを操作するためのより簡単な方法を提供すると思いますが、パイプはあなたの好みによりよく合うかもしれません。

:jQuery 1.8以降、deferred.pipe()非推奨になり、deferred.then置き換えられます。

于 2011-12-23T09:55:23.017 に答える
5

.then注:jquery 1.8以降では、の代わりに使用できます.pipe。この.then関数は新しいpromiseを返すように.pipeなり、不要になったため非推奨になりました。promiseの詳細については、promisesの仕様を参照してください。また、jqueryに依存しないjavascriptpromiseのよりクリーンなライブラリについてはq.jsを参照してください。

countries.reduce(function(l, r){
  return l.then(function(){return getData(r)});
}, $.Deferred().resolve());

q.jsを使用したい場合:

//create a closure for each call
function getCountry(c){return function(){return getData(c)};}
//fire the closures one by one
//note: in Q, when(p1,f1) is the static version of p1.then(f1)
countries.map(getCountry).reduce(Q.when, Q());

元の答え:

さらに別のパイプ。気弱な人向けではありませんが、もう少しコンパクトです。

countries.reduce(function(l, r){
  return l.pipe(function(){return getData(r)});
}, $.Deferred().resolve());

上記のコードがどのように機能するかを理解するためには、おそらくドキュメントを減らすのが最適です。基本的に、コールバックと初期値の2つの引数を取ります。

コールバックは配列のすべての要素に繰り返し適用され、最初の引数には前の反復の結果が供給され、2番目の引数は現在の要素になります。ここでの秘訣は、がjquerygetData()の遅延promiseを返すことです。パイプは、現在の要素でgetDataが呼び出される前に、前の要素のgetDataが完了していることを確認します。

2番目の引数$.Deferred().resolve()は、解決された遅延値のイディオムです。コールバック実行の最初の反復にフィードされ、最初の要素のgetDataがすぐに呼び出されるようにします。

于 2013-03-02T07:36:53.707 に答える
4

なぜこれを実行するのか正確にはわかりませんが、要求する必要のあるすべてのURLのリストを保持し、success関数が呼び出されるまで次のURLを要求しないでください。IEは、success条件付きでに追加の呼び出しを行いdeferredます。

于 2011-12-23T06:29:21.637 に答える
4

私はこれに遅れていることを知っていますが、あなたの元のコードはほとんど問題ないと思いますが、2つ(おそらく3つ)の問題があります。

パイプgetData(country)のパラメータをどのようにコーディングしたかにより、すぐに呼び出されます。あなたがそれを持っている方法は、getData()すぐに実行され、結果(ajaxの約束ですが、httpリクエストはすぐに始まります)がパラメータとしてに渡されますpipe()。したがって、コールバック関数を渡す代わりに、オブジェクトを渡します。これにより、パイプの新しい遅延がすぐに解決されます。

私はそれが必要だと思います

deferred.pipe(function () { return getData(country); });

これで、パイプの親の遅延が解決されたときに呼び出されるコールバック関数になりました。このようにコーディングすると、2番目の問題が発生します。延期されたマスターが解決されるまで、getData()は実行されません。

潜在的な3番目の問題は、すべてのパイプが延期されたマスターに接続されるため、実際にはチェーンがなく、とにかくすべて同時に実行されるのではないかと考えています。ドキュメントには、コールバックは順番に実行されると書かれていますが、コールバックはpromiseを返し、非同期で実行されるため、すべてがある程度並行して実行される可能性があります。

だから、私はあなたがこのようなものが必要だと思います

var countries = ["US", "CA", "MX"];
var deferred = $.Deferred();
var promise = deferred.promise();

$.each(countries, function(index, country) {
    promise = promise.pipe(function () { return getData(country); });
});

deferred.resolve();
于 2012-09-19T18:37:12.053 に答える
4

私はjQueryキューで成功しました。

$(function(){
    $.each(countries, function(i,country){
      $('body').queue(function() {
        getData(country);
      });
    });
});

var getData = function(country){
  $.ajax({
    url : 'ajax.jsp',
    data : { country : country },
    type : 'post',
    success : function() {                          
      // Que up next ajax call
      $('body').dequeue();
    },
    error : function(){
      $('body').clearQueue();
    }
  });
};
于 2013-07-03T17:32:44.583 に答える
2

更新: deferred.pipeは非推奨になりました

これは、jQueryAPIですでに文書化されているものの多くのコードです。http://api.jquery.com/deferred.pipe/を参照してください

100個すべてが完成するまで、それらを配管し続けることができます。

または、N回の呼び出しを行い、行われたすべての呼び出しのデータを使用して1つの関数を解決するための何かを作成しました。注:スーパーXHRオブジェクトではなくデータを返します。 https://gist.github.com/1219564

于 2012-02-13T02:39:16.007 に答える