Eu estava escrevendo um código que faz algo parecido com:
function getStuffDone(param) { | function getStuffDone(param) {
var d = Q.defer(); /* or $q.defer */ | return new Promise(function(resolve, reject) {
// or = new $.Deferred() etc. | // using a promise constructor
myPromiseFn(param+1) | myPromiseFn(param+1)
.then(function(val) { /* or .done */ | .then(function(val) {
d.resolve(val); | resolve(val);
}).catch(function(err) { /* .fail */ | }).catch(function(err) {
d.reject(err); | reject(err);
}); | });
return d.promise; /* or promise() */ | });
} | }
Alguém me disse que isso é chamado de " antipadrão diferido " ou " Promise
construtor antipadrão ", respectivamente, o que há de ruim nesse código e por que isso é chamado de antipadrão ?
javascript
promise
q
bluebird
es6-promise
Benjamin Gruenbaum
fonte
fonte
getStuffDone
wrapper da função e apenas usar o literal Promise?catch
bloco nogetStuffDone
invólucro o antipadrão?Promise
exemplo nativo, você também possui invólucros de funções desnecessários para os manipuladores.then
e.catch
(isto é, poderia ser.then(resolve).catch(reject)
). Uma tempestade perfeita de antipadrões.Respostas:
O antipadrão diferido (agora antipadrão de construção explícita) cunhado por Esailija é um povo antipadrão comum, que é novo nas promessas, eu mesmo fiz quando usei promessas pela primeira vez. O problema com o código acima é que falha ao utilizar o fato que promete a cadeia.
As promessas podem ser combinadas
.then
e você pode retornar as promessas diretamente. Seu códigogetStuffDone
pode ser reescrito como:As promessas são sobre tornar o código assíncrono mais legível e se comportar como código síncrono sem ocultar esse fato. Promessas representam uma abstração sobre um valor de uma operação única, abstraem a noção de uma declaração ou expressão em uma linguagem de programação.
Você só deve usar objetos adiados quando estiver convertendo uma API em promessas e não puder fazê-lo automaticamente, ou quando estiver escrevendo funções de agregação que sejam mais facilmente expressas dessa maneira.
Citando Esailija:
fonte
.defer()
api para o mais recente (e jogar seguro) construtor promessa, isso não aconteceu (de maneira nenhuma) depreciar a noção de promessas construindo :)O que há de errado com isso?
Sortudo. Infelizmente, provavelmente não, pois você provavelmente esqueceu de um caso de ponta. Em mais da metade das ocorrências que vi, o autor esqueceu de cuidar do manipulador de erros:
Se a outra promessa for rejeitada, isso acontecerá despercebido em vez de ser propagado para a nova promessa (onde seria tratada) - e a nova promessa permanecerá pendente para sempre, o que pode induzir vazamentos.
O mesmo acontece no caso em que seu código de retorno de chamada causa um erro - por exemplo, quando
result
não há umproperty
e uma exceção é lançada. Isso não seria tratado e deixaria a nova promessa por resolver.Por outro lado, o uso
.then()
cuida automaticamente desses dois cenários e rejeita a nova promessa quando ocorre um erro:O antipadrão diferido não é apenas pesado, mas também propenso a erros . Usar
.then()
para encadeamento é muito mais seguro.Mesmo? Boa. No entanto, isso será bastante detalhado e abundante, especialmente se você usar uma biblioteca de promessas que suporte outros recursos, como cancelamento ou passagem de mensagens. Ou talvez seja no futuro, ou você queira trocar sua biblioteca por uma melhor? Você não vai querer reescrever seu código para isso.
Os métodos das bibliotecas (
then
) não apenas suportam nativamente todos os recursos, mas também podem ter certas otimizações em vigor. Seu uso provavelmente tornará seu código mais rápido ou, pelo menos, permitirá que seja otimizado por futuras revisões da biblioteca.Como evito isso?
Assim, sempre que você encontrar-se criar manualmente um
Promise
ouDeferred
e promessas já existentes estão envolvidos, verificar a API biblioteca primeiro . O antipadrão diferido é frequentemente aplicado por pessoas que vêem [apenas] promessas como um padrão de observador - mas promessas são mais do que retornos de chamada : elas devem ser compostas. Toda biblioteca decente tem muitas funções fáceis de usar para a composição de promessas de todas as maneiras possíveis, cuidando de todas as coisas de baixo nível com as quais você não deseja lidar.Se você encontrou a necessidade de redigir algumas promessas de uma maneira nova que não é suportada por uma função auxiliar existente, escrever sua própria função com adiamentos inevitáveis deve ser sua última opção. Considere mudar para uma biblioteca mais abrangente e / ou registrar um bug na sua biblioteca atual. Seu mantenedor deve poder derivar a composição das funções existentes, implementar uma nova função auxiliar para você e / ou ajudar a identificar os casos extremos que precisam ser tratados.
fonte
setTimeout
, incluindo onde o construtor poderia ser usado, mas não ser considerado "Promit anitpattern constructor"?setTimeout
", mas " asetTimeout
própria função ".setTimeout
", mas" asetTimeout
própria função "". Pode descrever, vincular-se a diferenças entre os dois?setTimeout
é claramente diferente da própria funçãosetTimeout
, não é?