465

何が起こっているかの不自然な例を次に示します: http://jsfiddle.net/adamjford/YNGcm/20/

HTML:

<a href="#">Click me!</a>
<div></div>

JavaScript:

function getSomeDeferredStuff() {
    var deferreds = [];

    var i = 1;
    for (i = 1; i <= 10; i++) {
        var count = i;

        deferreds.push(
        $.post('/echo/html/', {
            html: "<p>Task #" + count + " complete.",
            delay: count
        }).success(function(data) {
            $("div").append(data);
        }));
    }

    return deferreds;
}

$(function() {
    $("a").click(function() {
        var deferreds = getSomeDeferredStuff();

        $.when(deferreds).done(function() {
            $("div").append("<p>All done!</p>");
        });
    });
});

「全部やった!」が欲しい すべての遅延タスクが完了した後に表示されますが、$.when()遅延オブジェクトの配列を処理する方法を知らないようです。"すべて完了!" 配列は Deferred オブジェクトではないため、最初に発生しているため、jQuery は先に進み、それが完了したと想定します。

オブジェクトを次のように関数に渡すことができることは知っています$.when(deferred1, deferred2, ..., deferredX)が、解決しようとしている実際の問題で実行時に Deferred オブジェクトがいくつあるかは不明です。

4

9 に答える 9

761

値の配列を、通常は個別のパラメーターであると予想される任意のFunction.prototype.apply関数に渡すには、 を使用します。この場合、次のものが必要です。

$.when.apply($, my_array).then( ___ );

http://jsfiddle.net/YNGcm/21/を参照

ES6 では、代わりに... スプレッド演算子を使用できます。

$.when(...my_array).then( ___ );

.thenどちらの場合でも、ハンドラーが必要とする仮パラメーターの数を事前に知ることはまずないため、そのハンドラーargumentsは各 promise の結果を取得するために配列を処理する必要があります。

于 2011-04-11T20:41:10.557 に答える
112

上記の回避策 (ありがとう!) は、遅延オブジェクトのメソッドに提供されたオブジェクトを取得する問題に適切に対処していません。jQuery は、配列ではなく個々のパラメーターを使用しておよびコールバックをresolve()呼び出すためです。つまり、疑似配列を使用して、遅延オブジェクトの配列によって返されたすべての解決/拒否されたオブジェクトを取得する必要があります。これは醜いです:done()fail()arguments

$.when.apply($,deferreds).then(function() {
     var objects = arguments; // The array of resolved objects as a pseudo-array
     ...
};

deferred の配列を渡したので、結果の配列を取得できれば便利です。のようなメソッドを使用できるように、疑似配列の代わりに実際の配列を取得することもできますArray.sort()

これらの問題に対処するwhen.jsのメソッドに触発されたソリューションを次に示します。when.all()

// Put somewhere in your scripting environment
if (typeof jQuery.when.all === 'undefined') {
    jQuery.when.all = function (deferreds) {
        return $.Deferred(function (def) {
            $.when.apply(jQuery, deferreds).then(
            // the calling function will receive an array of length N, where N is the number of
            // deferred objects passed to when.all that succeeded. each element in that array will
            // itself be an array of 3 objects, corresponding to the arguments passed to jqXHR.done:
            // ( data, textStatus, jqXHR )
            function () {
                var arrayThis, arrayArguments;

                if (Array.isArray(this)) {
                    arrayThis = this;
                    arrayArguments = arguments;
                }
                else {
                    arrayThis = [this];
                    arrayArguments = [arguments];
                }

                def.resolveWith(arrayThis, [Array.prototype.slice.call(arrayArguments)]);
            },
            // the calling function will receive an array of length N, where N is the number of
            // deferred objects passed to when.all that failed. each element in that array will
            // itself be an array of 3 objects, corresponding to the arguments passed to jqXHR.fail:
            // ( jqXHR, textStatus, errorThrown )
            function () {
                var arrayThis, arrayArguments;

                if (Array.isArray(this)) {
                    arrayThis = this;
                    arrayArguments = arguments;
                }
                else {
                    arrayThis = [this];
                    arrayArguments = [arguments];
                }

                def.rejectWith(arrayThis, [Array.prototype.slice.call(arrayArguments)]);
            });
        });
    }
}

次のように、単純に deferreds/promise の配列を渡して、解決済み/拒否されたオブジェクトの配列をコールバックで取得できます。

$.when.all(deferreds).then(function(objects) {
    console.log("Resolved objects:", objects);
});
于 2013-04-25T06:53:16.180 に答える
38

whenメソッドを配列に適用できます。

var arr = [ /* Deferred objects */ ];

$.when.apply($, arr);

jQuery Deferred の配列をどのように操作しますか?

于 2011-04-11T20:48:01.087 に答える
8

複数の並列 AJAX 呼び出しを呼び出す場合、それぞれの応答を処理するための 2 つのオプションがあります。

  1. 同期 AJAX 呼び出しを使用する/ 次々に使用する/ 非推奨
  2. すべてのs がそれぞれの応答で正常に返されると、 sを受け入れるPromises'配列とそのコールバックが呼び出されます。$.whenpromise.donepromise

function ajaxRequest(capitalCity) {
   return $.ajax({
        url: 'https://restcountries.eu/rest/v1/capital/'+capitalCity,
        success: function(response) {
        },
        error: function(response) {
          console.log("Error")
        }
    });
}
$(function(){
   var capitalCities = ['Delhi', 'Beijing', 'Washington', 'Tokyo', 'London'];
   $('#capitals').text(capitalCities);

   function getCountryCapitals(){ //do multiple parallel ajax requests
      var promises = [];   
      for(var i=0,l=capitalCities.length; i<l; i++){
            var promise = ajaxRequest(capitalCities[i]);
            promises.push(promise);
      }
  
      $.when.apply($, promises)
        .done(fillCountryCapitals);
   }
  
   function fillCountryCapitals(){
        var countries = [];
        var responses = arguments;
        for(i in responses){
            console.dir(responses[i]);
            countries.push(responses[i][0][0].nativeName)
        }  
        $('#countries').text(countries);
   }
  
   getCountryCapitals()
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
  <h4>Capital Cities : </h4> <span id="capitals"></span>
  <h4>Respective Country's Native Names : </h4> <span id="countries"></span>
</div>

于 2015-07-18T20:18:12.370 に答える
4

$.each を使用して別のものを提案したい:

  1. 次のような ajax 関数を宣言できます。

    function ajaxFn(someData) {
        this.someData = someData;
        var that = this;
        return function () {
            var promise = $.Deferred();
            $.ajax({
                method: "POST",
                url: "url",
                data: that.someData,
                success: function(data) {
                    promise.resolve(data);
                },
                error: function(data) {
                    promise.reject(data);
                }
            })
            return promise;
        }
    }
    
  2. 送信する ajax を使用して関数の配列を作成するコードの一部:

    var arrayOfFn = [];
    for (var i = 0; i < someDataArray.length; i++) {
        var ajaxFnForArray = new ajaxFn(someDataArray[i]);
        arrayOfFn.push(ajaxFnForArray);
    }
    
  3. そして、ajax を送信して関数を呼び出します。

    $.when(
        $.each(arrayOfFn, function(index, value) {
            value.call()
        })
    ).then(function() {
            alert("Cheer!");
        }
    )
    
于 2016-09-22T09:24:19.103 に答える
1

トランスパイルしていて ES6 にアクセスできる場合は、オブジェクトの反復可能な各項目を個別の引数として具体的に適用するスプレッド構文を、必要な方法で使用できます$.when()

$.when(...deferreds).done(() => {
    // do stuff
});

MDN リンク - 拡散構文

于 2016-10-19T21:05:31.667 に答える
-1

angularJS または Q promise ライブラリのバリアントを使用している場合は、.all()この問題を正確に解決する方法があります。

var savePromises = [];
angular.forEach(models, function(model){
  savePromises.push(
    model.saveToServer()
  )
});

$q.all(savePromises).then(
  function success(results){...},
  function failed(results){...}
);

完全な API を参照してください。

https://github.com/kriskowal/q/wiki/API-Reference#promiseall

https://docs.angularjs.org/api/ng/service/$q

于 2014-07-21T19:56:02.183 に答える