Tenho uma série de promessas que estou resolvendo com Promise.all(arrayOfPromises);
Eu continuo a cadeia de promessas. Parece algo como isto
existingPromiseChain = existingPromiseChain.then(function() {
var arrayOfPromises = state.routes.map(function(route){
return route.handler.promiseHandler();
});
return Promise.all(arrayOfPromises)
});
existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
// do stuff with my array of resolved promises, eventually ending with a res.send();
});
Quero adicionar uma instrução catch para lidar com uma promessa individual, caso ocorra um erro, mas, quando tento, Promise.all
retorna o primeiro erro encontrado (desconsidera o restante) e não consigo obter os dados do restante das promessas em a matriz (que não errou).
Eu tentei fazer algo como ..
existingPromiseChain = existingPromiseChain.then(function() {
var arrayOfPromises = state.routes.map(function(route){
return route.handler.promiseHandler()
.then(function(data) {
return data;
})
.catch(function(err) {
return err
});
});
return Promise.all(arrayOfPromises)
});
existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
// do stuff with my array of resolved promises, eventually ending with a res.send();
});
Mas isso não resolve.
Obrigado!
-
Editar:
O que as respostas abaixo disseram eram completamente verdadeiras, o código estava quebrando devido a outros motivos. Caso alguém esteja interessado, esta é a solução que eu acabei com ...
Cadeia de servidores Node Express
serverSidePromiseChain
.then(function(AppRouter) {
var arrayOfPromises = state.routes.map(function(route) {
return route.async();
});
Promise.all(arrayOfPromises)
.catch(function(err) {
// log that I have an error, return the entire array;
console.log('A promise failed to resolve', err);
return arrayOfPromises;
})
.then(function(arrayOfPromises) {
// full array of resolved promises;
})
};
Chamada de API (rota.async chamada)
return async()
.then(function(result) {
// dispatch a success
return result;
})
.catch(function(err) {
// dispatch a failure and throw error
throw err;
});
Colocar o .catch
for Promise.all
antes do .then
parece ter servido ao objetivo de capturar quaisquer erros das promessas originais, mas retornar a matriz inteira para a próxima.then
Obrigado!
.then(function(data) { return data; })
pode ser completamente omitidothen
oucatch
e se houver um erro dentro dele. A propósito, esse nó é?Respostas:
Promise.all
é tudo ou nada. Ele resolve quando todas as promessas da matriz são resolvidas ou rejeitadas assim que uma delas rejeitar. Em outras palavras, ele resolve com uma matriz de todos os valores resolvidos ou rejeita com um único erro.Algumas bibliotecas têm algo chamado
Promise.when
, que eu entendo esperaria que todas as promessas na matriz resolvessem ou rejeitassem, mas não estou familiarizado com isso e não está no ES6.Seu código
Concordo com outras pessoas aqui que sua correção deve funcionar. Ele deve resolver com uma matriz que pode conter uma mistura de valores bem-sucedidos e objetos de erros. É incomum passar objetos de erro no caminho do sucesso, mas, supondo que seu código os esteja esperando, não vejo problema nisso.
A única razão pela qual consigo pensar por que "não resolveria" é que está falhando no código que você não está nos mostrando e o motivo pelo qual não está recebendo nenhuma mensagem de erro sobre isso é porque essa cadeia de promessas não é finalizada com uma final catch (tanto quanto o que você está nos mostrando).
Tomei a liberdade de levar em consideração a "corrente existente" do seu exemplo e encerrar a corrente com uma pegadinha. Isso pode não ser adequado para você, mas para as pessoas que estão lendo isso, é importante sempre retornar ou encerrar cadeias, ou erros em potencial, até mesmo erros de codificação, ficarão ocultos (que é o que suspeito que aconteceu aqui):
fonte
Promise.allSettled()
com suporte decente. Veja referência .Promise.all
falha quando o primeiro thread falha. Infelizmente, porém, todos os outros threads ainda continuam em execução até serem concluídos. Nada é cancelado, ainda pior: não há como cancelar um threadPromise
. Portanto, o que quer que os threads estejam fazendo (e manipulando) eles continuam, eles mudam de estado e variável, usam CPU, mas no final não retornam seu resultado. Você precisa estar ciente disso para não causar um caos, por exemplo, quando você repete / repete a chamada.NOVA RESPOSTA
API do FUTURE Promise
fonte
e
não precise ser umError
. Pode ser uma string, por exemplo, se alguém retornar como elaPromise.reject('Service not available')
..then()
e.catch()
.Promise.resolve()
passaria valor para o primeiro, enquantoPromise.reject()
passaria para o último. Você pode envolvê-los em objeto, por exemplo:p.then(v => ({success: true, value: v})).catch(e => ({success: false, error: e}))
.Para continuar o
Promise.all
loop (mesmo quando uma promessa rejeita), escrevi uma função de utilitário chamadaexecuteAllPromises
. Esta função de utilitário retorna um objeto comresults
eerrors
.A idéia é que todas as promessas
executeAllPromises
pelas quais você passa sejam envolvidas em uma nova promessa que sempre será resolvida. A nova promessa resolve com uma matriz que tem 2 pontos. O primeiro ponto mantém o valor de resolução (se houver) e o segundo ponto mantém o erro (se a Promessa finalizada rejeitar).Como etapa final,
executeAllPromises
acumula todos os valores das promessas agrupadas e retorna o objeto final com uma matriz pararesults
e uma matriz paraerrors
.Aqui está o código:
fonte
O ES2020 apresenta um novo método para o tipo Promise:
Promise.allSettled()
Promise.allSettled fornece um sinal quando todas as promessas de entrada são liquidadas, o que significa que elas são cumpridas ou rejeitadas. Isso é útil nos casos em que você não se importa com o estado da promessa, apenas quer saber quando o trabalho está concluído, independentemente de ter sido bem-sucedido.
Leia mais na postagem do blog da v8 https://v8.dev/features/promise-combinators
fonte
Como o @jib disse,
No entanto, você pode controlar certas promessas que "podem" falhar e gostaríamos de prosseguir
.then
.Por exemplo.
fonte
se você usar a biblioteca q https://github.com/kriskowal/q, ela possui o método q.allSettled () que pode solucionar esse problema, você pode lidar com todas as promessas, dependendo de seu estado, sendo preenchidas ou rejeitadas
fonte
q
), seria mais útil se você fornecesse um exemplo de uso relacionado à pergunta. Como está, sua resposta não explica como essa biblioteca pode ajudar a resolver o problema.Usando o Async aguardam -
aqui uma função assíncrona func1 está retornando um valor resolvido, e func2 está gerando um erro e retornando um nulo nessa situação, podemos lidar com isso como queremos e retornar adequadamente.
A saída é - ['func1', nulo]
fonte
Para aqueles que usam o ES8 que tropeçam aqui, você pode fazer algo como o seguinte, usando funções assíncronas :
fonte
Podemos lidar com a rejeição no nível de promessas individuais; portanto, quando obtivermos os resultados em nossa matriz de resultados, o índice da matriz que foi rejeitada será
undefined
. Podemos lidar com essa situação conforme necessário e usar os resultados restantes.Aqui eu rejeitei a primeira promessa, então ela é indefinida, mas podemos usar o resultado da segunda promessa, que está no índice 1.
fonte
Você já considerou
Promise.prototype.finally()
?Parece ter sido projetado para fazer exatamente o que você deseja - executar uma função depois que todas as promessas forem estabelecidas (resolvidas / rejeitadas), independentemente de algumas das promessas serem rejeitadas.
Na documentação MDN :
o
finally()
método pode ser útil se você desejar fazer algum processamento ou limpeza assim que a promessa for estabelecida, independentemente do resultado.O
finally()
método é muito semelhante a chamar.then(onFinally, onFinally)
mas existem algumas diferenças:Ao criar uma função embutida, você pode transmiti-la uma vez, em vez de ser forçado a declará-la duas vezes ou criar uma variável para ela.
Um retorno de chamada finalmente não receberá nenhum argumento, pois não há meios confiáveis para determinar se a promessa foi cumprida ou rejeitada. Esse caso de uso é exatamente quando você não se importa com o motivo da rejeição ou o valor da satisfação e, portanto, não há necessidade de fornecê-lo.
Diferente
Promise.resolve(2).then(() => {}, () => {})
(que será resolvido com indefinido),Promise.resolve(2).finally(() => {})
será resolvido com 2. Da mesma forma, diferente dePromise.reject(3).then(() => {}, () => {})
(que será cumprido com indefinido),Promise.reject(3).finally(() => {})
será rejeitado com 3.== Fallback ==
Se sua versão do JavaScript não suportar,
Promise.prototype.finally()
você pode usar esta solução alternativa de Jake Archibald :Promise.all(promises.map(p => p.catch(() => undefined)));
fonte
Promises.allSettled()
seja realmente implementado (documentado pelo MDN aqui ),Promises.all.finally()
parece que ele realizará a mesma coisa. Estou prestes a dar-lhe uma tentativa ...allSettled()
.allSettled()
ainda não está implementado em nenhum lugar, então não quero ficar à frente da realidade. Eu tive sucesso comPromises.all(myPromiseArray).finally()
, e isso se encaixa com esta resposta. Uma vez queallSettled()
realmente exista, posso testá-lo e descobrir como ele realmente funciona. Até então, quem sabe o que os navegadores realmente implementarão? A menos que você tem informação recente ao contrário ...Promise.allSettled
não está implementado no Firefox, mas parece existir no Chrome. Só porque os documentos dizem que foi implementado não significa que realmente seja implementado. Não vou usá-lo tão cedo.Como alternativa, se você tiver um caso em que não se preocupa particularmente com os valores das promessas resolvidas quando há uma falha, mas ainda deseja que elas sejam executadas, você pode fazer algo assim que resolverá com as promessas normalmente quando todos têm sucesso e rejeitam as promessas fracassadas quando alguma delas falha:
fonte
Você sempre pode agrupar sua promessa retornando funções de uma maneira que elas detectem falhas e retornem um valor acordado (por exemplo, mensagem de erro), para que a exceção não role até a função Promise.all e a desative.
fonte
Eu encontrei uma maneira (solução alternativa) de fazer isso sem torná-lo sincronizado.
Então, como foi mencionado antes, não
Promise.all
há nada.então ... Use uma promessa anexa para capturar e forçar a resolução.
fonte
Você precisaria saber como identificar um erro nos seus resultados. Se você não tiver um erro esperado padrão, sugiro que você execute uma transformação em cada erro no bloco de captura que o identifique nos resultados.
fonte
Não é a melhor maneira de registrar erros, mas sempre é possível definir tudo para uma matriz para o promessaTodos e armazenar os resultados resultantes em novas variáveis.
Se você usa o graphQL, precisa pós-processar a resposta independentemente e, se ela não encontrar a referência correta, ele travará o aplicativo, restringindo a localização do problema.
fonte
É assim que
Promise.all
é projetado para funcionar. Se uma única promessa for cumpridareject()
, todo o método falhará imediatamente.Existem casos de uso em que se pode querer que as
Promise.all
promessas falhem. Para fazer isso acontecer, simplesmente não use nenhumareject()
declaração em sua promessa. No entanto, para garantir que seu aplicativo / script não congele, caso nenhuma promessa subjacente nunca receba uma resposta, é necessário colocar um tempo limite nela.fonte
reject()
sua promessa é bom, mas e se você precisar usar as promessas de outra biblioteca?Eu escrevi uma biblioteca npm para lidar com esse problema mais bonito. https://github.com/wenshin/promiseallend
Instalar
25-02-2017 nova API, não são princípios de promessa de quebra
—————————————————————————
API ruim antiga, não a use!
fonte
Promise.all
. Mas ele coletará todos os dados e erros de todas as promessas. também suporta entrada de objetos, não faz sentido. depois de coletar todos os dados e erros, substituo opromise.then
método para lidar com os retornos de chamada registrados, que incluem rejeitados e atendidos. Para mais detalhes você pode ver o códigoonFulfilled
eonRejected
manipuladores que são passados parathen
?fulfilled
erejected
. Mas, na verdade, faz com que um problema difícil seja compatível com todos os casos de uso prometidos normalmente, comoonFulfilled
eonRejected
todos retornamPromise.reject()
ouPromise.resolve()
. Até agora não estou claro como resolvê-lo, alguém tem uma idéia melhor? A melhor resposta por enquanto tem um problema é que ele pode não filtrar dados e erros no ambiente do navegador.