5

私がここで誤解していることについての洞察に感謝します。私の要件は次のとおりです。

URLの配列があります。各URLのAJAXリクエストを同時に実行したいのですが、最初のリクエストが完了したらすぐに、最初のコールバックを呼び出します。次に、2番目のリクエストが完了したら、そのコールバックを呼び出します。

オプション1:

for (var i = 0; i < myUrlArray.length; i++) {
    $.ajax({
        url: myUrlArray[i]
    }).done(function(response) {
        // Do something with response
    });
}

応答が正しい順序で完了する保証がないため、明らかにこれは機能しません。

オプション2:

var promises = [];
for (var i = 0; i < myUrlArray.length; i++) {
    promises.push($.ajax({
        url: myUrlArray[i]
    }));
}
$.when.apply($, promises).then(function() {
    // Do something with each response
});

これは機能するはずですが、欠点は、すべてのAJAXリクエストが完了するまで待機してから、コールバックを起動することです。

理想的には、最初のコールバックが完了したらすぐに呼び出し、次に2番目のコールバックをチェーンして、その応答が受信されるたびに(または、すでに解決されている場合はすぐに)実行し、3番目というように続けます。

配列の長さは完全に可変であり、いつでも任意の数のリクエストを含めることができるため、コールバックチェーンをハードコーディングすることはオプションではありません。

私の試み:

var promises = [];
for (var i = 0; i < myUrlArray.length; i++) {
    promises.push($.ajax({
        url: myUrlArray[i] // Add each AJAX Deferred to the promises array
    }));
}
(function handleAJAX() {
    var promise;
    if (promises.length) {
        promise = promises.shift(); // Grab the first one in the stack
        promise.then(function(response) { // Set up 'done' callback
            // Do something with response

            if (promises.length) {
                handleAJAX(); // Move onto the next one
            }
        });
    }
}());

問題は、コールバックが完全にランダムな順序で実行されることです。たとえば、配列に「home.html」、「page2.html」、「page3.html」を追加した場合、応答の順序は必ずしも「home.html」、「page2.html」、「page3」になるとは限りません。 .html'。

私は明らかに、約束が機能する方法について何かを根本的に誤解しています。どんな助けでもありがたいことに感謝します!

乾杯

編集

OK、今はさらに混乱しています。このJSFiddleは、 Alnitakの回答を使用した配列とJoeFletchの回答を使用した別の配列で作成しましたが、どちらも期待どおりに機能しません。誰かがここで何が起こっているのか見ることができますか?

編集2

動作しました!以下のJoeFletchの回答に基づいて、私は次のようにソリューションを適応させました。

var i, responseArr = [];

for (i = 0; i < myUrlArray.length; i++) {
    responseArr.push('0'); // <-- Add 'unprocessed' flag for each pending request
    (function(ii) {
        $.ajax({
            url: myUrlArray[ii]
        }).done(function(response) {
            responseArr[ii] = response; // <-- Store response in array
        }).fail(function(xhr, status, error) {
            responseArr[ii] = 'ERROR';
        }).always(function(response) {
            for (var iii = 0; iii < responseArr.length; iii++) { // <-- Loop through entire response array from the beginning
                if (responseArr[iii] === '0') {
                    return; // As soon as we hit an 'unprocessed' request, exit loop
                }
                else if (responseArr[iii] !== 'done') {
                    $('#target').append(responseArr[iii]); // <-- Do actual callback DOM append stuff
                    responseArr[iii] = 'done'; // <-- Set 'complete' flag for this request
                }
            }
        });
    }(i)); // <-- pass current value of i into closure to encapsulate
}

TL; DR: jQueryの約束がわかりません。それがなくても、機能します。:)

4

3 に答える 3

6

コールバックをすぐに登録する必要がないことを忘れないでください。

あなたのコードとの主な違いは、数行をリファクタリングするのではなく、使用したことです.done.then

var promises = myUrlArray.map(function(url) {
    return $.ajax({url: url});
});

(function serialize() {
    var def = promises.shift();
    if (def) {
        def.done(function() {
            callback.apply(null, arguments);
            serialize();
        });
    }
})();
于 2012-11-08T20:05:18.833 に答える
3

非同期リクエストは、送信されたのと同じ順序で完了するとは限りません。サーバーの負荷と転送されるデータの量によっては、他のものよりも時間がかかる場合があります。

唯一のオプションは、それらがすべて完了するまで待つか、一度に 1 つずつ送信するか、またはおそらく順不同で呼び出された場合に対処することです。

于 2012-11-08T20:04:51.233 に答える
3

これを解決するための私の試みは次のとおりです。.ajax失敗した呼び出しのエラー処理を含めるように回答を更新しました。また、一部のコードを呼び出しのcompleteメソッドに移動しました。.ajax

var urlArr = ["url1", "url2"];
var responseArr = [];
for(var i = 0; i < length; i++) {
    responseArr.push("0");//0 meaning unprocessed to the DOM
}

$.each(urlArr, function(i, url){
    $.ajax({
        url: url,
        success: function(data){
            responseArr[i] = data;
        },
        error: function (xhr, status, error) {
            responseArr[i] = "Failed Response";//enter whatever you want to place here to notify the end user
        },
        complete: function() {
           $.each(responseArr, function(i, element){
                if (responseArr[i] == "0") {
                    return;
                }
                else if (responseArr[i] != "done")
                {
                    //do something with the response
                    responseArr[i] = "done";
                }
            });
        }
    });
})
于 2012-11-08T20:12:35.847 に答える