Aqui está um exemplo artificial do que está acontecendo: 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>");
});
});
});
Eu quero "Tudo pronto!" apareça após a conclusão de todas as tarefas adiadas, mas $.when()
não parece saber como lidar com uma matriz de objetos adiados . "Tudo feito!" está acontecendo primeiro porque o array não é um objeto Adiado, portanto, o jQuery segue em frente e assume que acabou de terminar.
Eu sei que é possível passar os objetos para a função, $.when(deferred1, deferred2, ..., deferredX)
mas não se sabe quantos objetos adiados haverá em execução no problema real que estou tentando resolver.
javascript
jquery
argument-passing
jquery-deferred
.when
adamjford
fonte
fonte
$.when.apply
obter o mesmo resultado.Respostas:
Para passar uma matriz de valores para qualquer função que normalmente espera que sejam parâmetros separados, use
Function.prototype.apply
, portanto, neste caso, você precisa:Consulte http://jsfiddle.net/YNGcm/21/
No ES6, você pode usar o
...
operador de spread :Em qualquer um dos casos, como é improvável que você saiba com antecedência quantos parâmetros formais o
.then
manipulador precisará, esse manipulador precisaria processar aarguments
matriz para recuperar o resultado de cada promessa.fonte
$.when
-f.apply(ctx, my_array)
irá chamarf
comthis == ctx
e os argumentos definidos para o conteúdo demy_array
.$
vsnull
como o primeiro parâmetro vale uma leitura. Nesse caso em particular, não importa.$
é menos digitadonull
e você está seguro quando a$.when
implementação é alterada (não é provável que neste caso, mas por que não manterthis
inalterado por padrão).As soluções alternativas acima (obrigado!) Não abordam adequadamente o problema de retornar os objetos fornecidos ao
resolve()
método do adiado, porque o jQuery chama os retornos de chamadadone()
efail()
com parâmetros individuais, não uma matriz. Isso significa que precisamos usar oarguments
pseudo-array para obter todos os objetos resolvidos / rejeitados retornados pelo array de diferidos, o que é feio:Como passamos uma série de adiados, seria bom recuperar uma série de resultados. Também seria bom recuperar uma matriz real em vez de uma pseudo-matriz, para que possamos usar métodos como
Array.sort()
.Aqui está uma solução inspirada por when.js 's
when.all()
método que aborda estes problemas:Agora você pode simplesmente passar uma matriz de adiados / promessas e recuperar uma matriz de objetos resolvidos / rejeitados em seu retorno de chamada, assim:
fonte
var toArray = function (args) { return deferreds.length > 1 ? $.makeArray(args) : [args]; }
vez deArray.prototype.slice.call
.Você pode aplicar o
when
método à sua matriz:Como você trabalha com uma matriz de adiados jQuery?
fonte
Ao chamar várias chamadas paralelas AJAX, você tem duas opções para manipular as respectivas respostas.
Promises'
array e$.when
que aceitepromise
s e seu retorno de chamada.done
seja chamado quando todos ospromise
s retornarem com êxito com as respectivas respostas.Exemplo
fonte
$.when
.for ... in
em uma matriz ?!)(not recommended)
2.Não concordo -for ... in
está ok porque a matriz contém apenas as propriedades necessárias (sem propriedades extras). obrigado de qualquer maneiraArray.prototype
. De qualquer forma, para código que não seja crítico para o desempenho, seria melhor usar em.map
vez de um loopfor
/push
, por exemplovar promises = capitalCities.map(ajaxRequest); $.when.apply($, promises).then(fillCountryCapitals)
- trabalho concluído.Como uma alternativa simples, que não exige
$.when.apply
ouarray
você pode usar o seguinte padrão para gerar uma única promessa para várias promessas paralelas:por exemplo
Notas:
promise = promise.then(newpromise)
fonte
then()
chamadas em cadeia de maneira semelhante. O comportamento com$.when
é agir como é paralelo (não encadeado). Por favor, tente-lo antes de jogar fora uma alternativa útil, pois funciona :)Quero propor outro usando $ .each:
Podemos declarar a função ajax como:
Parte do código onde criamos uma matriz de funções com o ajax para enviar:
E chamando funções com o envio de ajax:
fonte
Se você estiver transpilando e tiver acesso ao ES6, poderá usar a sintaxe de propagação, que aplica especificamente cada item iterável de um objeto como um argumento discreto, da maneira que for
$.when()
necessária.Link MDN - Sintaxe de propagação
fonte
Se você estiver usando angularJS ou alguma variante da biblioteca Q promessa, então você tem um
.all()
método que resolve esse problema exato.veja a API completa:
https://github.com/kriskowal/q/wiki/API-Reference#promiseall
https://docs.angularjs.org/api/ng/service/$q
fonte
.map
aqui, mas tudo bem).Eu tive um caso muito parecido em que eu estava postando em cada loop e, em seguida, definindo a marcação html em alguns campos dos números recebidos do ajax. Eu então precisava fazer uma soma dos valores (agora atualizados) desses campos e colocar em um campo total.
Assim, o problema era que eu estava tentando fazer uma soma em todos os números, mas nenhum dado havia chegado ainda das chamadas assíncronas ajax. Eu precisava concluir essa funcionalidade em algumas funções para poder reutilizar o código. Minha função externa aguarda os dados antes de eu fazer algumas coisas com o DOM totalmente atualizado.
fonte