Quando então (sucesso, fracasso) é considerado um antipadrão para promises?

Eu tive um olhar para o FAQ promise bluebird , em que menciona que. .then(success, fail) é um antipadrão . Eu não entendo bem sua explicação quanto à tentativa e captura. O que há de errado com isso o seguinte?

 some_promise_call() .then(function(res) { logger.log(res) }, function(err) { logger.log(err) }) 

Parece que o exemplo está sugerindo o seguinte como o caminho correto.

 some_promise_call() .then(function(res) { logger.log(res) }) .catch(function(err) { logger.log(err) }) 

Qual é a diferença?

Qual é a diferença?

A chamada .then() retornará uma promise que será rejeitada caso o retorno de chamada lance um erro. Isso significa que, quando o logger sucesso falhar, o erro será passado para o seguinte retorno de chamada .catch() , mas não para o retorno de chamada com fail que acompanha o success .

Aqui está um diagrama de stream de controle :

controle diagrama de fluxo de então com dois argumentosdiagrama de fluxo de controle da cadeia de captura

Para expressá-lo em código síncrono:

 // some_promise_call().then(logger.log, logger.log) then: { try { var results = some_call(); } catch(e) { logger.log(e); break then; } // else logger.log(results); } 

O segundo log (que é como o primeiro argumento para. .then() ) só será executado no caso de nenhuma exceção acontecer. O bloco rotulado e a instrução break parecem um pouco estranhos, isto é, na verdade, o que o python tem try-except-else para (leitura recomendada!).

 // some_promise_call().then(logger.log).catch(logger.log) try { var results = some_call(); logger.log(results); } catch(e) { logger.log(e); } 

O logger de catch também manipulará exceções da chamada do logger de sucesso.

Tanto pela diferença.

Eu não entendo muito bem a sua explicação quanto à tentativa e captura

O argumento é que geralmente você quer pegar erros em todas as etapas do processamento, e que você não deve usá-lo em cadeias. A expectativa é que você tenha apenas um manipulador final que manipule todos os erros – enquanto, quando você usa o “antipattern”, erros em algumas das chamadas de retorno não são tratados.

No entanto, esse padrão é realmente muito útil: quando você deseja manipular erros que aconteceram exatamente nesta etapa e deseja fazer algo totalmente diferente quando não ocorreu nenhum erro, ou seja, quando o erro é irrecuperável. Esteja ciente de que isso está ramificando seu stream de controle. Claro, isso às vezes é desejado.


O que há de errado com isso o seguinte?

 some_promise_call() .then(function(res) { logger.log(res) }, function(err) { logger.log(err) }) 

Que você teve que repetir seu retorno de chamada. Você prefere

 some_promise_call() .catch(function(e) { return e; // it's OK, we'll just log it }) .done(function(res) { logger.log(res); }); 

Você também pode considerar o uso de .finally() para isso.

Os dois não são exatamente idênticos. A diferença é que o primeiro exemplo não detecta uma exceção lançada no manipulador de success . Portanto, se o seu método deve retornar apenas promises resolvidas, como é frequentemente o caso, você precisa de um manipulador de catch à direita (ou ainda outro com um parâmetro de success vazio). Claro, pode ser que o seu manipulador não faça nada que possa potencialmente falhar, em cujo caso usar um parâmetro de 2 pode ser bom.

Mas acredito que o ponto do texto ao qual você está vinculado é que then é mais útil em comparação com callbacks em sua capacidade de encadear um monte de etapas assíncronas, e quando você realmente faz isso, a forma de 2 parâmetros de then sutilmente não se comporta como esperado, pelo motivo acima. É particularmente contra-intuitivo quando usado no meio da cadeia.

Como alguém que fez um monte de coisas assíncronas complexas e esbarrou em cantos como este mais do que eu gostaria de admitir, eu realmente recomendo evitar esse antipadrão e seguir com a abordagem de manipulador separado.

Ao olhar para as vantagens e desvantagens de ambos, podemos fazer um palpite calculado sobre o que é apropriado para a situação. Estas são as duas principais abordagens para implementar promises. Ambos têm suas vantagens e desvantagens

Abordagem de Captura

 some_promise_call() .then(function(res) { logger.log(res) }) .catch(function(err) { logger.log(err) }) 

Vantagens

  1. Todos os erros são manipulados por um bloco catch.
  2. Até pega alguma exceção no bloco de então.
  3. Encadeamento de vários callbacks de sucesso

Desvantagens

  1. No caso de encadeamento, torna-se difícil mostrar mensagens de erro diferentes.

Abordagem de sucesso / erro

 some_promise_call() .then(function success(res) { logger.log(res) }, function error(err) { logger.log(err) }) 

Vantagens

  1. Você obtém um controle de erros granulado.
  2. Você pode ter uma function comum de tratamento de erros para várias categorias de erros, como erro de db, erro de 500 etc.

Desvalorização

  1. Você ainda precisará de outra catch se desejar erros de manipulador lançados pelo callback de sucesso

Em vez de palavras, bom exemplo. Código a seguir (se a primeira promise foi resolvida):

 Promise.resolve() .then ( () => { throw new Error('Error occurs'); }, err => console.log('This error is caught:', err) ); 

é idêntico a:

 Promise.resolve() .catch ( err => console.log('This error is caught:', err) ) .then ( () => { throw new Error('Error occurs'); } ) 

Mas com a primeira promise rejeitada, isso não é idêntico:

 Promise.reject() .then ( () => { throw new Error('Error occurs'); }, err => console.log('This error is caught:', err) ); Promise.reject() .catch ( err => console.log('This error is caught:', err) ) .then ( () => { throw new Error('Error occurs'); } )