Wie arbeiten Sie mit einer Reihe von jQuery Deferreds?

Ich habe eine Anwendung, die Daten in einer bestimmten Reihenfolge geladen werden muss: die Stamm-URL, dann die Schemas, dann schließlich die Anwendung mit den Schemas und URLs für die verschiedenen Datenobjekte initialisieren. Während der Benutzer die Anwendung navigiert, werden Datenobjekte geladen, anhand des Schemas validiert und angezeigt. Wenn der Benutzer die Daten CRUDs, bieten die Schemas First-Pass-validation.

Ich habe ein Problem mit der Initialisierung. Ich verwende einen Ajax-Aufruf, um das Wurzelobjekt $ .when () abzurufen, und erstelle dann ein Array von Versprechen, eines für jedes Schemaobjekt. Das funktioniert. Ich sehe den Abruf in der Konsole.

Ich sehe dann den Abruf für alle Schemas, so dass jeder Aufruf von $ .ajax () funktioniert. fetchschemas () gibt tatsächlich ein Array von Versprechen zurück.

Diese finale, wenn () -Klausel jedoch nie ausgetriggers wird und das Wort “FERTIG” nie auf der Konsole angezeigt wird. Der Quellcode von jquery-1.5 scheint zu implizieren, dass “null” als Objekt akzeptabel ist, das an $ .when.apply () übergeben wird, da when () ein internes Deferred () – Objekt zum Verwalten der Liste erstellt, wenn kein Objekt vorhanden ist eingefahren.

Dies funktionierte mit Futures.js. Wie sollte eine Reihe von jQuery Deferreds verwaltet werden, wenn nicht so?

var fetch_schemas, fetch_root; fetch_schemas = function(schema_urls) { var fetch_one = function(url) { return $.ajax({ url: url, data: {}, contentType: "application/json; charset=utf-8", dataType: "json" }); }; return $.map(schema_urls, fetch_one); }; fetch_root = function() { return $.ajax({ url: BASE_URL, data: {}, contentType: "application/json; charset=utf-8", dataType: "json" }); }; $.when(fetch_root()).then(function(data) { var promises = fetch_schemas(data.schema_urls); $.when.apply(null, promises).then(function(schemas) { console.log("DONE", this, schemas); }); }); 

   

Du schaust nach

 $.when.apply($, promises).then(function(schemas) { console.log("DONE", this, schemas); }, function(e) { console.log("My ajax failed"); }); 

Das wird auch funktionieren (für einen Wert der Arbeit wird es keinen gebrochenen Ajax reparieren):

 $.when.apply($, promises).done(function() { ... }).fail(function() { ... });` 

Sie sollten $ anstelle von null damit sich this innerhalb von $.when auf jQuery bezieht. Es sollte für die Quelle keine Rolle spielen, aber es ist besser, als null .

Verspotte all deine $ .ajax, indem du sie durch $.when und das Beispiel funktioniert

Es ist also entweder ein Problem in Ihrer Ajax-Anfrage oder das Array, das Sie an fetch_schemas übergeben.

Die obige Problemumgehung (thank!) Behebt das Problem der Rückgabe der Objekte, die der Methode resolve() der Deferred-Methode zur Verfügung gestellt wurden, nicht richtig, da jQuery die callbacke done() und fail() mit einzelnen Parametern und nicht mit einem Array aufruft. Das bedeutet, dass wir das arguments pseudo-array verwenden müssen, um alle aufgetriggersen / zurückgewiesenen Objekte zu erhalten, die von dem Array von Deferred zurückgegeben werden, was hässlich ist:

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

Da wir eine Reihe von Deferred-Elementen übergeben haben, wäre es schön, eine Reihe von Ergebnissen zu erhalten. Es wäre auch schön, anstelle eines Pseudo-Arrays ein tatsächliches Array zu bekommen, so dass wir Methoden wie Array.sort() .

Hier ist eine Lösung, die von der when.js when.all() -Methode inspiriert wurde, die diese Probleme when.all() :

 // Put somewhere in your scripting environment if (jQuery.when.all===undefined) { jQuery.when.all = function(deferreds) { var deferred = new jQuery.Deferred(); $.when.apply(jQuery, deferreds).then( function() { deferred.resolve(Array.prototype.slice.call(arguments)); }, function() { deferred.fail(Array.prototype.slice.call(arguments)); }); return deferred; } } 

Jetzt können Sie einfach ein Array von Deferred / Versprochen übergeben und erhalten ein Array von aufgetriggersen / abgelehnten Objekten in Ihrem Callback, so:

 $.when.all(promises).then(function(schemas) { console.log("DONE", this, schemas); // 'schemas' is now an array }, function(e) { console.log("My ajax failed"); }); 

Wenn Sie die ES6-Version von JavaScript verwenden Es gibt einen Spread-Operator (…), der Array von Objekten in kommagetrennte Argumente konvertiert.

 $.when(...promises).then(function() { var schemas=arguments; }; 

Weitere Informationen zum ES6-Spread-Operator https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator finden Sie hier

verlängert sich mit diesem Code:

 var rawWhen = $.when $.when = function(promise) { if ($.isArray(promise)) { var dfd = new jQuery.Deferred() rawWhen.apply($, promise).done(function() { dfd.resolve(Array.prototype.slice.call(arguments)) }).fail(function() { dfd.reject(Array.prototype.slice.call(arguments)) }) return dfd.promise() } else { return rawWhen.apply($, arguments) } }