Come lavori con una serie di jQuery Deferreds?

Ho un’applicazione che richiede che i dati vengano caricati in un determinato ordine: l’URL di root, quindi gli schemi, quindi finalmente inizializzare l’applicazione con gli schemi e gli URL per i vari oggetti di dati. Mentre l’utente naviga l’applicazione, gli oggetti dati vengono caricati, convalidati rispetto allo schema e visualizzati. Come CRUD utente i dati, gli schemi forniscono la convalida di primo passaggio.

Sto avendo un problema con l’inizializzazione. Io uso una chiamata Ajax per recuperare l’object radice, $ .when (), e quindi creare una serie di promesse, una per ogni object schema. Che funzioni. Vedo il recupero nella console.

Vedo quindi il recupero per tutti gli schemi, quindi ogni chiamata $ .ajax () funziona. fetchschemas () in effetti restituisce una serie di promesse.

Tuttavia, quella finale quando () non si triggers mai e la parola “DONE” non appare mai sulla console. Il codice sorgente di jquery-1.5 sembra implicare che “null” sia accettabile come object da passare a $ .when.apply (), poiché when () costruirà un object interno Deferred () per gestire l’elenco se nessun object è passato dentro

Questo ha funzionato usando Futures.js. Come dovrebbe essere gestito un array di jQuery Deferred, se non in questo modo?

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

Stai cercando

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

Funzionerà anche (per un certo valore di lavoro, non aggiusterà l’ajax spezzata):

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

Dovrai passare $ invece di null modo che this all’interno di $.when riferisce a jQuery . Non dovrebbe avere importanza per la fonte, ma è meglio passare null .

Ha derubato tutti i $ .ajax sostituendoli con $.when e l’esempio funziona

Quindi è un problema nella tua richiesta Ajax o il tuo array passa a fetch_schemas.

La soluzione sopra descritta (grazie!) Non risolve correttamente il problema di recuperare gli oggetti forniti al metodo resolve() posticipato poiché jQuery chiama i callback done() e fail() con i singoli parametri, non con una matrice. Ciò significa che dobbiamo utilizzare gli arguments pseudo-array per ottenere tutti gli oggetti risolti / rifiutati restituiti dall’array di differiti, che è brutto:

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

Dato che siamo passati in una serie di differiti, sarebbe bello tornare a una serie di risultati. Sarebbe anche bello recuperare una matrice vera e propria invece di uno pseudo-array, così possiamo usare metodi come Array.sort() .

Ecco una soluzione ispirata al metodo when.all() che risolve questi problemi:

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

Ora puoi semplicemente passare una serie di posticipi / promesse e recuperare una serie di oggetti risolti / rifiutati nella tua richiamata, in questo modo:

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

Se stai usando la versione ES6 di javascript, c’è un operatore di spread (…) che converte array di oggetti in argomenti separati da virgole.

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

Maggiori informazioni sull’operatore di spread ES6 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator trovano qui

si estende quando con questo codice:

 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) } }