Preciso de um loop que aguarde uma chamada assíncrona antes de continuar. Algo como:
for ( /* ... */ ) {
someFunction(param1, praram2, function(result) {
// Okay, for cycle could continue
})
}
alert("For cycle ended");
Como posso fazer isso? Você tem alguma ideia?
javascript
Casar com Hoffser
fonte
fonte
( /* ... */ )
parece um monstro e estou com medo agora :(Respostas:
Você não pode misturar síncrono e assíncrono em JavaScript se bloquear o script, bloquear o navegador.
Você precisa seguir o caminho todo voltado para o evento aqui, felizmente podemos esconder as coisas feias.
EDIT: Atualizado o código.
Isso nos fornecerá um sistema assíncrono
loop
, você pode, é claro, modificá-lo ainda mais para usar, por exemplo, uma função para verificar a condição do loop etc.Agora vamos ao teste:
E a saída:
fonte
loop.break()
fazer? Só uma forma de forçar a saída, se quiser?Eu simplifiquei isso:
FUNÇÃO:
USO:
EXEMPLO: http://jsfiddle.net/NXTv7/8/
fonte
Uma alternativa mais limpa para o que @Ivo sugeriu seria uma Fila de método assíncrono , supondo que você só precise fazer uma chamada assíncrona para a coleção.
(Veja esta postagem de Dustin Diaz para uma explicação mais detalhada)
Você simplesmente cria uma nova instância de
Queue
, adiciona os retornos de chamada de que precisa e, em seguida, libera a fila com a resposta assíncrona.Um benefício adicional desse padrão é que você pode adicionar várias funções à fila, em vez de apenas uma.
Se você tem um objeto que contém funções de iterador, pode adicionar suporte para essa fila nos bastidores e escrever um código que parece síncrono, mas não é:
simplesmente escreva
each
para colocar a função anônima na fila em vez de executá-la imediatamente e, em seguida, libere a fila quando a chamada assíncrona for concluída. Este é um padrão de design muito simples e poderoso.PS Se você estiver usando jQuery, você já tem uma fila de métodos assíncronos à sua disposição chamada jQuery.Deferred .
fonte
someFunction
quais atrasem o resto do loop, seu padrão configura uma lista de funções que serão executadas em ordem e todas receberão os resultados de uma outra chamada de função. É um bom padrão, mas não acho que corresponda à pergunta em questão.setTimeout
. Você corre o risco de um comportamento indesejado se o código for executado mais rápido do que o previsto.setTimeout
se o retorno de chamada levar apenas metade do tempo, bem, o código executa mais rápido novamente ... então qual é o ponto? O "código" no "loop" ainda está em ordem, se você fizer algumas coisas fora dele antes do retorno de chamada completo, você já está chamando por problemas, mas, novamente, é de thread único, é difícil encontrar um cenário ondesetTimeout
quebraria algo, sem mais mal-design.Veja também esta esplêndida biblioteca caolan / async . Seu
for
loop pode ser facilmente realizado usando mapSeries ou series .Eu poderia postar algum código de exemplo se seu exemplo tivesse mais detalhes nele.
fonte
Também podemos usar a ajuda de jquery.Deferred. neste caso, a função asyncLoop ficaria assim:
a função de retorno de chamada será semelhante a esta:
função de exemplo que resolve adiado:
fonte
Tenho usado o comando "setTimeout (Func, 0);" truque por cerca de um ano. Aqui estão algumas pesquisas recentes que escrevi para explicar como acelerá-lo um pouco. Se você quiser apenas a resposta, pule para a Etapa 4. As etapas 1, 2 e 3 explicam o raciocínio e a mecânica;
fonte
Dada uma função de trabalho assíncrona
someFunction
que chamará de volta uma função de resultado com umresult
argumento dizendo se o loop deve ou não continuar:Para verificar se termina ou não o loop, a função de trabalho
someFunction
pode encaminhar a função de resultado para outras operações assíncronas. Além disso, toda a expressão pode ser encapsulada em uma função assíncrona, tomando uma funçãodone
como retorno de chamada.fonte
Se você gosta da resposta de wilsonpage, mas está mais acostumado a usar a sintaxe do async.js, aqui está uma variação:
A demonstração pode ser encontrada aqui - http://jsfiddle.net/NXTv7/8/
fonte
Aqui está outro exemplo que eu acho que é mais legível do que outros, onde você envolve sua função assíncrona dentro de uma função que leva em uma
done
função, o índice de loop atual e o resultado (se houver) da chamada assíncrona anterior:Uma vez
done()
chamado, ele dispara a próxima chamada assíncrona, novamente passando a função concluída, o índice atual e o resultado anterior. Assim que todo o loop for concluído, o loop fornecidocallback
será invocado.Aqui está um snippet que você pode executar:
fonte
Você pode usar o
async await
introduzido no ES7:Isso funciona apenas se
someFunction
estiver retornando uma promessa!Se
someFunction
não estiver retornando uma promessa, você pode fazer com que ela retorne uma promessa por si mesmo, assim:Em seguida, substitua esta linha
await someFunction(param1, param2);
porawait asynSomeFunction(param1, param2);
Por favor, entenda o Promises antes de escrever o
async await
código!fonte
Unexpected await inside loop
.javascript
problema. Esse aviso surge de suaeslint
configuração. Eu sempre desabilito essa regraeslint
porque na maioria dos lugares que eu realmente preciso esperar dentro do loophttp://cuzztuts.blogspot.ro/2011/12/js-async-for-very-cool.html
EDITAR:
link do github: https://github.com/cuzzea/lib_repo/blob/master/cuzzea/js/functions/core/async_for.js
Esta função permite que você crie uma porcentagem de quebra no loop for usando settings.limit. A propriedade limit é apenas um inteiro, mas quando definida como array.length * 0.1, fará com que settings.limit_callback seja chamado a cada 10%.
exemplo:
fonte
Uma solução baseada em biblioteca promissora:
fonte
Eu precisava chamar alguns
X
tempos de função assíncrona , cada iteração deve ter acontecido depois que a anterior foi feita, então eu escrevi uma pequena biblioteca que pode ser usada assim:Cada vez que a função de loop definida pelo usuário é chamada, ela tem dois argumentos, índice de iteração e valor de retorno da chamada anterior.
Este é um exemplo de saída:
fonte