Ainda sou bastante novo nas promessas e atualmente estou usando o bluebird, no entanto, tenho um cenário em que não tenho certeza de como lidar melhor com isso.
Por exemplo, eu tenho uma cadeia de promessas em um aplicativo expresso da seguinte forma:
repository.Query(getAccountByIdQuery)
.catch(function(error){
res.status(404).send({ error: "No account found with this Id" });
})
.then(convertDocumentToModel)
.then(verifyOldPassword)
.catch(function(error) {
res.status(406).send({ OldPassword: error });
})
.then(changePassword)
.then(function(){
res.status(200).send();
})
.catch(function(error){
console.log(error);
res.status(500).send({ error: "Unable to change password" });
});
Então, o comportamento que eu busco é:
- Vai obter a conta por ID
- Se houver uma rejeição neste momento, bombardeie e retorne um erro
- Se não houver erro, converta o documento retornado para um modelo
- Verifique a senha com o documento do banco de dados
- Se as senhas não corresponderem, bombardeie e retorne um erro diferente
- Se não houver erro, altere as senhas
- Então retorne o sucesso
- Se algo mais der errado, retorne 500
Portanto, atualmente, as capturas não parecem interromper o encadeamento, e isso faz sentido, por isso estou me perguntando se existe uma maneira de forçar de alguma forma a cadeia a parar em um determinado ponto com base nos erros ou se existe uma maneira melhor estruturar isso para obter algum tipo de comportamento de ramificação, como é o caso if X do Y else Z
.
Qualquer ajuda seria ótimo.
javascript
node.js
promise
bluebird
Grofit
fonte
fonte
Respostas:
Esse comportamento é exatamente como um lançamento síncrono:
Isso é metade do ponto de
.catch
- ser capaz de se recuperar de erros. Pode ser desejável tentar novamente para sinalizar que o estado ainda é um erro:No entanto, isso por si só não funcionará no seu caso, pois o erro foi detectado por um manipulador posterior. O problema real aqui é que os manipuladores de erro generalizados "HANDLE ANYTHING" são uma prática ruim em geral e são extremamente desaprovados em outras linguagens de programação e ecossistemas. Por esse motivo, o Bluebird oferece capturas digitadas e predicadas.
A vantagem adicional é que sua lógica de negócios não precisa (nem deveria) estar ciente do ciclo de solicitação / resposta. Não é responsabilidade da consulta decidir qual status e erro HTTP o cliente recebe e, posteriormente, à medida que seu aplicativo cresce, você pode separar a lógica de negócios (como consultar seu banco de dados e como processar seus dados) do que você envia ao cliente (qual código de status http, qual texto e qual resposta).
Aqui está como eu escreveria seu código.
Primeiro, eu
.Query
jogaria umaNoSuchAccountError
subclasse daPromise.OperationalError
qual o Bluebird já fornece. Se você não souber como subclassificar um erro, entre em contato.Além disso, eu a subclassificaria
AuthenticationError
e faria algo como:Como você pode ver - é muito limpo e você pode ler o texto como um manual de instruções do que acontece no processo. Também é separado da solicitação / resposta.
Agora, eu chamaria isso do manipulador de rota como tal:
Dessa forma, a lógica está tudo em um só lugar e a decisão de como lidar com os erros do cliente está em um só lugar e eles não se confundem.
fonte
.catch(someSpecificError)
manipulador intermediário para algum erro específico é se você deseja capturar um tipo específico de erro (que é inofensivo), lidar com ele e continuar o fluxo a seguir. Por exemplo, eu tenho algum código de inicialização que tem uma sequência de coisas a fazer. A primeira coisa é ler o arquivo de configuração do disco, mas se esse arquivo de configuração estiver faltando, será um erro OK (o programa possui padrões internos) para que eu possa lidar com esse erro específico e continuar o restante do fluxo. Também pode haver limpeza melhor para não sair até mais tarde.instanceof
chceks manualmente manualmente..catch
funciona como atry-catch
declaração, o que significa que você só precisa de uma captura no final:fonte
Não. Você não pode realmente "terminar" uma corrente, a menos que você lance uma exceção que borbulha até o fim. Veja a resposta de Benjamin Gruenbaum para saber como fazer isso.
A derivação de seu padrão seria não para distinguir tipos de erro, mas usar erros que têm
statusCode
ebody
campos que podem ser enviados a partir de um único, genérico.catch
manipulador. Dependendo da estrutura da sua aplicação, a solução dele pode ser mais limpa.Sim, você pode fazer ramificações com promessas . No entanto, isso significa deixar a cadeia e "voltar" ao aninhamento - assim como você faria em uma declaração aninhada if-else ou try-catch:
fonte
Eu tenho feito desta maneira:
Você deixa a sua pegada no final. E basta lançar um erro quando isso acontece no meio da sua cadeia.
Suas outras funções provavelmente se pareceriam com isso:
fonte
Provavelmente um pouco tarde para a festa, mas é possível aninhar
.catch
como mostrado aqui:Mozilla Developer Network - Usando promessas
Editar: enviei isso porque ele fornece a funcionalidade solicitada em geral. No entanto, não neste caso particular. Porque, como explicado em detalhes por outros já,
.catch
deve recuperar o erro. Você não pode, por exemplo, enviar uma resposta para o cliente em vários.catch
retornos de chamada porque um.catch
sem explícitasreturn
resolve -lo comundefined
, nesse caso, causando processo.then
para acionar embora sua cadeia não é realmente resolvido, potencialmente causando uma sequência.catch
de gatilho e enviando outra resposta ao cliente, causando um erro e provavelmente jogando doUnhandledPromiseRejection
seu jeito. Espero que essa sentença complicada faça algum sentido para você.fonte
Em vez de
.then().catch()...
você pode fazer.then(resolveFunc, rejectFunc)
. Essa cadeia de promessas seria melhor se você lidasse com as coisas ao longo do caminho. Aqui está como eu o reescreveria:Nota: A
if (error != null)
é um pouco de um truque para interagir com o erro mais recente.fonte
Penso que a resposta de Benjamin Gruenbaum acima é a melhor solução para uma sequência lógica complexa, mas aqui está a minha alternativa para situações mais simples. Eu apenas uso uma
errorEncountered
bandeira junto comreturn Promise.reject()
para pular quaisquer declaraçõesthen
oucatch
declarações subseqüentes . Então ficaria assim:Se você tiver mais de dois pares then / catch, provavelmente deverá usar a solução de Benjamin Gruenbaum. Mas isso funciona para uma configuração simples.
Observe que a final
catch
tem apenas,return;
e nãoreturn Promise.reject();
, porque não há subseqüentesthen
que precisamos pular, e isso contaria como uma rejeição de Promessa não tratada, da qual o Node não gosta. Como está escrito acima, a finalcatch
retornará uma Promessa pacificamente resolvida.fonte