Como você trabalha com uma matriz de jQuery Deferreds?

Eu tenho um aplicativo que requer que os dados sejam carregados em uma determinada ordem: a URL raiz, depois os esquemas e, finalmente, inicializá-lo com os esquemas e URLs dos vários objects de dados. À medida que o usuário navega pelo aplicativo, os objects de dados são carregados, validados no esquema e exibidos. Conforme o usuário faz o CRUD dos dados, os esquemas fornecem validação de primeira passagem.

Estou tendo um problema com a boot. Eu uso uma chamada Ajax para buscar o object raiz, $ .when () e, em seguida, criar uma matriz de promises, uma para cada object de esquema. Isso funciona. Eu vejo a busca no console.

Então eu vejo a busca de todos os esquemas, então cada chamada $ .ajax () funciona. fetchschemas () de fato retorna uma série de promises.

No entanto, essa cláusula when () final nunca é acionada e a palavra “DONE” nunca aparece no console. O código-fonte para jquery-1.5 parece implicar que “null” é aceitável como um object para passar para $ .when.apply (), como quando () criará um object interno Deferred () para gerenciar a lista se nenhum object for Transmitido.

Isso funcionou usando Futures.js. Como uma matriz de jQuery Deferreds deve ser gerenciada, se não for assim?

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

    Você está procurando

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

    Isso também funcionará (para algum valor de trabalho, ele não consertará ajax quebrado):

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

    Você vai querer passar $ vez de null para que this dentro $.when se refere a jQuery . Não importa para a fonte, mas é melhor do que passar null .

    Zombei de todos os seus $ .ajax substituindo-os por $.when e a amostra funciona

    Portanto, é um problema em sua solicitação de ajax ou na matriz que você passa para fetch_schemas.

    A solução alternativa acima (obrigado!) Não resolve adequadamente o problema de recuperar os objects fornecidos para o método resolve() do deferred porque o jQuery chama os callbacks done() e fail() com parâmetros individuais, não um array. Isso significa que temos que usar a pseudo-matriz de arguments para obter todos os objects resolvidos / rejeitados retornados pela matriz de deferreds, que é feia:

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

    Desde que passamos em uma matriz de diferidos, seria bom recuperar uma série de resultados. Também seria bom recuperar um array real em vez de um pseudo array para que possamos usar methods como Array.sort() .

    Aqui está uma solução inspirada no método when.all() que trata desses problemas:

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

    Agora você pode simplesmente passar uma matriz de adiamentos / promises e recuperar uma matriz de objects resolvidos / rejeitados no seu retorno de chamada, assim:

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

    Se você estiver usando a versão ES6 do javascript Existe um operador de dispersão (…) que converte a matriz de objects em argumentos separados por vírgulas.

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

    Mais sobre o operador de propagação do ES6 https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Operators/Spread_operator

    estende quando com este código:

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