Eu gostaria de esclarecer esse ponto, pois a documentação não é muito clara sobre isso;
Q1: O Promise.all(iterable)
processamento de todas as promessas é seqüencial ou paralelo? Ou, mais especificamente, é o equivalente a executar promessas encadeadas como
p1.then(p2).then(p3).then(p4).then(p5)....
ou é algum outro tipo de algoritmo onde todos p1
, p2
, p3
, p4
, p5
, etc. estão sendo chamados ao mesmo tempo (em paralelo) e os resultados são devolvidos assim que tudo resolve (ou se rejeita)?
P2: Se for Promise.all
executado em paralelo, existe uma maneira conveniente de executar um iterável sequencialmente?
Nota : Não quero usar Q ou Bluebird, mas todas as especificações nativas do ES6.
javascript
node.js
promise
es6-promise
Yanick Rochon
fonte
fonte
Promise.all
executa em paralelo.node.js
eio.js
como é aqui que estou usando. Então, sim, a implementação da V8, se você preferir.Promise.all
.new Promise(a).then(b); c();
a é executado primeiro, depois c, então b. Não é Promise. Tudo o que executa essas promessas, ele apenas lida quando elas são resolvidas.Respostas:
Não, as promessas não podem "ser executadas". Eles iniciam sua tarefa quando estão sendo criados - eles representam apenas os resultados - e você está executando tudo em paralelo, mesmo antes de passá-los para
Promise.all
.Promise.all
aguarda apenas várias promessas. Não se importa em que ordem eles resolvem ou se os cálculos estão sendo executados em paralelo.Se você já tem suas promessas, não pode fazer muito, mas
Promise.all([p1, p2, p3, …])
(que não tem uma noção de sequência). Mas se você tiver uma iterável de funções assíncronas, poderá executá-las sequencialmente. Basicamente, você precisa sair depara
e a solução para fazer isso é usar
Array::reduce
:fonte
then
sequência - o valor de retorno é a promessa do últimofn
resultado, e você pode encadear outros retornos de chamada.fn1().then(p2).then(fn3).catch(…
? Não há necessidade de usar uma expressão de função.retValFromF1
é passadop2
, é exatamente o quep2
faz. Claro, se você quiser fazer mais (passar variáveis adicionais, ligue para múltiplas funções, etc) você precisa usar uma expressão de função, embora a mudançap2
na matriz seria mais fáciliterable
é o[fn1, fn2, fn3, …]
conjuntoEm paralelo
Vantagens: Mais rápido. Todas as iterações serão executadas mesmo se uma falhar.
Em sequência
Vantagens: Variáveis no loop podem ser compartilhadas por cada iteração. Comporta-se como um código síncrono imperativo normal.
fonte
for (const item of items) await fetchItem(item);
await Promise.all(items.map(async item => { return await fetchItem(item).catch(e => e) }))
async
função é uma chamada de API e você não deseja DDOS o servidor. Você tem melhor controle sobre os resultados individuais e erros gerados na execução. Ainda melhor, você pode decidir quais erros continuar e o que interromper o ciclo.A resposta da Bergis me colocou no caminho certo usando Array.reduce.
No entanto, para realmente obter as funções retornando minhas promessas de executar uma após a outra, tive que adicionar mais alguns aninhamentos.
Meu caso de uso real é uma matriz de arquivos que eu preciso transferir em ordem um após o outro, devido a limites a jusante ...
Aqui está o que eu acabei.
Como as respostas anteriores sugerem, use:
não esperou a conclusão da transferência antes de iniciar outra e também o texto "Todos os arquivos transferidos" veio antes mesmo que a primeira transferência de arquivo fosse iniciada.
Não tenho certeza do que fiz de errado, mas queria compartilhar o que funcionou para mim.
Edit: Desde que escrevi este post, agora entendo por que a primeira versão não funcionou. então () espera uma função retornando uma promessa. Portanto, você deve passar o nome da função sem parênteses! Agora, minha função quer um argumento, então eu preciso envolver uma função anônima sem argumento!
fonte
apenas para elaborar a resposta de @ Bergi (que é muito sucinta, mas difícil de entender;)
Esse código executará cada item na matriz e adicionará o próximo 'cadeia em seguida' ao final;
espero que isso faça sentido.
fonte
Você também pode processar uma iterável sequencialmente com uma função assíncrona usando uma função recursiva. Por exemplo, dada uma matriz
a
para processar com a função assíncronasomeAsyncFunction()
:fonte
array.prototype.reduce
é muito melhor em termos de desempenho de uma função recursivareduce
local em que você precisa construir toda athen()
cadeia em uma etapa e depois executar.Usando async aguardam, uma série de promessas pode ser facilmente executada sequencialmente:
Nota: Na implementação acima, se uma promessa for rejeitada, o restante não será executado. Se você quiser que todas as suas promessas sejam executadas, envolva seu
await a[i]();
interiortry catch
fonte
paralelo
veja este exemplo
executando o código, ele consola "CHAMADO" para todas as seis promessas e, quando são resolvidas, consola a cada 6 respostas após o tempo limite ao mesmo tempo
fonte
O NodeJS não executa promessas em paralelo, executa-as simultaneamente, pois é uma arquitetura de loop de eventos com thread único. Existe a possibilidade de executar as coisas em paralelo, criando um novo processo filho para aproveitar a CPU com múltiplos núcleos.
Parallel Vs Concurent
De fato, o que
Promise.all
faz é empilhar a função promessas na fila apropriada (consulte a arquitetura do loop de eventos), executando-as simultaneamente (chame P1, P2, ...), aguardando cada resultado e resolvendo o Promise.all com todas as promessas. resultados. Promise.all falhará na primeira promessa que falhar, a menos que você mesmo tenha gerenciado a rejeição.Há uma grande diferença entre paralelo e simultâneo, o primeiro executará computação diferente em processo separado exatamente ao mesmo tempo e progredirá a esse ritmo, enquanto o outro executará a computação diferente, um após o outro, sem esperar pelo anterior. computação para terminar e progredir ao mesmo tempo, sem depender um do outro.
Por fim, para responder à sua pergunta,
Promise.all
não será executado nem em paralelo nem em sequência, mas simultaneamente.fonte
A resposta de Bergi me ajudou a tornar a chamada síncrona. Adicionei um exemplo abaixo em que chamamos cada função depois que a função anterior é chamada.
fonte
Você pode fazer isso pelo loop for.
promessa de retorno de função assíncrona
se você escrever o código a seguir, o cliente será criado paralelamente
todos os clientes são criados paralelamente. mas se você deseja criar um cliente sequencialmente, deve usar o loop for
todos os clientes são criados sequencialmente.
codificação feliz :)
fonte
async
/await
está disponível apenas com um transpiler ou usando outros mecanismos que não o Node. Além disso, você realmente não deve misturarasync
comyield
. Quando eles agem da mesma forma com um transpilador eco
, na verdade, são bem diferentes e normalmente não devem se subdividir . Além disso, você deve mencionar essas restrições, pois sua resposta é confusa para programadores iniciantes.Eu tenho usado por para resolver promessas sequenciais. Não tenho certeza se isso ajuda aqui, mas é isso que tenho feito.
fonte
isso pode responder parte de sua pergunta.
sim, você pode encadear uma matriz de funções de retorno prometidas da seguinte forma ... (isso passa o resultado de cada função para a próxima). é claro que você pode editá-lo para passar o mesmo argumento (ou nenhum argumento) para cada função.
fonte
Eu tropecei nesta página enquanto tentava resolver um problema no NodeJS: remontagem de blocos de arquivos. Basicamente: eu tenho uma variedade de nomes de arquivos. Preciso anexar todos esses arquivos, na ordem correta, para criar um arquivo grande. Eu devo fazer isso de forma assíncrona.
O módulo 'fs' do nó fornece appendFileSync, mas eu não queria bloquear o servidor durante esta operação. Eu queria usar o módulo fs.promises e encontrar uma maneira de encadear essas coisas. Os exemplos nesta página não funcionaram para mim porque eu realmente precisava de duas operações: fsPromises.read () para ler no bloco de arquivos e fsPromises.appendFile () para concatenar com o arquivo de destino. Talvez se eu fosse melhor com javascript, poderia ter feito as respostas anteriores funcionarem para mim. ;-)
Eu tropecei neste ... https://css-tricks.com/why-using-reduce-to-sequentially-resolve-promises-works/ ... e consegui hackear uma solução de trabalho.
TLDR:
E aqui está um teste de unidade de jasmim para ele:
Eu espero que isso ajude alguém.
fonte