471 Stimmen

Übergeben Sie ein Array von Deferreds an $.when()

Hier ist ein konstruiertes Beispiel dafür: 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>");
        });
    });
});

Ich möchte, dass "Alles erledigt!" erscheint, wenn alle aufgeschobenen Aufgaben erledigt sind, aber $.when() scheint nicht zu wissen, wie man mit einem Array von Deferred-Objekten umgeht. "All done!" geschieht zuerst, weil das Array nicht ein Deferred-Objekt ist, so jQuery geht voran und nimmt an, es ist gerade fertig.

Ich weiß, dass man die Objekte an die Funktion übergeben könnte wie $.when(deferred1, deferred2, ..., deferredX) aber es ist nicht bekannt, wie viele Deferred-Objekte es bei der Ausführung des eigentlichen Problems, das ich zu lösen versuche, geben wird.

766voto

Alnitak Punkte 324207

So übergeben Sie ein Array von Werten an jede Funktion, die normalerweise erwartet, dass sie separate Parameter sind, verwenden Sie Function.prototype.apply In diesem Fall brauchen Sie also:

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

Voir http://jsfiddle.net/YNGcm/21/

In ES6 können Sie die ... Spread-Operator stattdessen:

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

In jedem Fall ist es unwahrscheinlich, dass Sie im Voraus wissen, wie viele formale Parameter die .then Handler benötigen wird, müsste dieser Handler die arguments Array, um das Ergebnis eines jeden Versprechens abzurufen.

112voto

crispyduck Punkte 1742

Die obigen Abhilfen (danke!) gehen nicht richtig auf das Problem ein, die Objekte zurückzubekommen, die dem deferred's resolve() Methode, denn jQuery ruft die done() y fail() Rückrufe mit einzelnen Parametern, nicht mit einem Array. Das bedeutet, wir müssen die arguments Pseudo-Array, um alle aufgelösten/abgelehnten Objekte zu erhalten, die vom Array der Deferreds zurückgegeben werden, was hässlich ist:

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

Da wir ein Array von Deferreds übergeben haben, wäre es schön, ein Array von Ergebnissen zurückzubekommen. Es wäre auch schön, ein tatsächliches Array anstelle eines Pseudo-Arrays zurückzubekommen, damit wir Methoden verwenden können wie Array.sort() .

Hier ist eine Lösung, die von wenn.js 's when.all() Methode, die diese Probleme löst:

// 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)]);
            });
        });
    }
}

Jetzt können Sie einfach ein Array von Deferreds/Promises übergeben und ein Array von aufgelösten/abgelehnten Objekten in Ihrem Callback zurückbekommen, etwa so:

$.when.all(deferreds).then(function(objects) {
    console.log("Resolved objects:", objects);
});

39voto

Eli Punkte 16649

Sie können die when Methode zu Ihrem Array hinzufügen:

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

$.when.apply($, arr);

Wie arbeitet man mit einem Array von jQuery Deferreds?

10voto

vinayakj Punkte 5415

Wenn Sie mehrere parallele AJAX-Aufrufe tätigen, haben Sie zwei Möglichkeiten, die jeweiligen Antworten zu behandeln.

  1. Synchrone AJAX-Aufrufe verwenden/ nacheinander/ nicht empfohlen
  2. Utilisez Promises' Array und $.when die akzeptiert promise s und dessen Rückruf .done wird aufgerufen, wenn alle promise s werden erfolgreich mit den entsprechenden Antworten zurückgegeben.

Beispiel

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>

5voto

Gone Coding Punkte 90304

Eine einfache Alternative, die nicht erforderlich ist $.when.apply oder ein array können Sie das folgende Muster verwenden, um ein einzelnes Versprechen für mehrere parallele Versprechen zu erzeugen:

promise = $.when(promise, anotherPromise);

z.B..

function GetSomeDeferredStuff() {
    // Start with an empty resolved promise (or undefined does the same!)
    var promise;
    var i = 1;
    for (i = 1; i <= 5; i++) {
        var count = i;

        promise = $.when(promise,
        $.ajax({
            type: "POST",
            url: '/echo/html/',
            data: {
                html: "<p>Task #" + count + " complete.",
                delay: count / 2
            },
            success: function (data) {
                $("div").append(data);
            }
        }));
    }
    return promise;
}

$(function () {
    $("a").click(function () {
        var promise = GetSomeDeferredStuff();
        promise.then(function () {
            $("div").append("<p>All done!</p>");
        });
    });
});

Anmerkungen:

  • Ich habe das herausgefunden, nachdem ich gesehen habe, wie jemand Versprechen sequentiell verkettet hat, indem er promise = promise.then(newpromise)
  • Der Nachteil ist, dass hinter den Kulissen zusätzliche Versprechensobjekte erstellt werden und die am Ende übergebenen Parameter nicht sehr nützlich sind (da sie in zusätzlichen Objekten verschachtelt sind). Für das, was Sie wollen, ist es jedoch kurz und einfach.
  • Der Vorteil ist, dass kein Array oder Array-Management erforderlich ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X