Eu tenho lido sobre adiados e promessas do jQuery e não vejo a diferença entre usar .then()
& .done()
para retornos de chamada bem-sucedidos. Eu sei que Eric Hynds menciona isso .done()
e .success()
mapeia para a mesma funcionalidade, mas acho que o faz, .then()
pois todos os retornos de chamada são invocados na conclusão de uma operação bem-sucedida.
Alguém pode me esclarecer sobre o uso correto?
jquery
promise
jquery-deferred
screenm0nkey
fonte
fonte
Respostas:
Os retornos de chamada anexados
done()
serão acionados quando o adiado for resolvido. Os retornos de chamada anexadosfail()
serão acionados quando o adiado for rejeitado.Antes do jQuery 1.8,
then()
era apenas açúcar sintático:A partir do 1.8,
then()
é um alias parapipe()
e retorna uma nova promessa, veja aqui para obter mais informações sobrepipe()
.success()
eerror()
estão disponíveis apenas nojqXHR
objeto retornado por uma chamada paraajax()
. Eles são aliases simples paradone()
efail()
respectivamente:Além disso,
done()
não se limita a um único retorno de chamada e filtrará as não funções (embora exista um bug com as strings na versão 1.8 que deve ser corrigido na 1.8.1):O mesmo vale para
fail()
.fonte
then
devolver uma nova promessa era uma coisa essencial que me faltava. Eu não conseguia entender por que uma corrente como$.get(....).done(function(data1) { return $.get(...) }).done(function(data2) { ... })
estava falhando comdata2
indefinida; quando mudeidone
parathen
ele funcionou, porque eu estava realmente querendo prometer juntos, em vez de anexar mais manipuladores à promessa original.done
outhen
? Por quê?.then()
).Também há diferença na maneira como os resultados de retorno são processados (é chamado encadeamento,
done
nãothen
encadeia enquanto produz cadeias de chamada)Os seguintes resultados serão registrados:
Enquanto
obterá o seguinte:
---------- Atualização:
Btw. Esqueci de mencionar, se você retornar um valor de Promessa em vez de tipo atômico, a promessa externa aguardará até que a promessa interna seja resolvida:
dessa maneira, torna-se muito simples compor operações assíncronas paralelas ou sequenciais, como:
O código acima emite duas solicitações http em paralelo, tornando as solicitações concluídas mais rapidamente, enquanto abaixo dessas solicitações http estão sendo executadas sequencialmente, reduzindo a carga do servidor
fonte
done
não faz nada no resultado em quethen
altera o resultado. Enorme ponto perdido pelos outros imo.then
mudou em 1,8done
ethen
chama.done
exemplo. Alterethen
parapipe
no pré-1.8 para obter othen
comportamento 1.8+ ..done()
tem apenas um retorno de chamada e é o retorno de sucesso.then()
tem retornos de chamada com êxito e com falha.fail()
possui apenas um retorno de chamada com falhaentão depende de você o que você deve fazer ... você se importa se é bem-sucedido ou se falha?
fonte
then()
muito diferentesdone()
. Comothen()
geralmente é chamado apenas com o retorno de chamada bem-sucedido, seu ponto é mais um detalhe do que a principal coisa a lembrar / conhecer. (Não posso dizer como era antes do jQuery 3.0.)deferred.done ()
adiciona manipuladores a serem chamados somente quando Adiado for resolvido . Você pode adicionar vários retornos de chamada para serem chamados.
Você também pode escrever acima assim,
deferred.then ()
adiciona manipuladores a serem chamados quando adiado for resolvido, rejeitado ou ainda estiver em andamento .
fonte
then
se comporta se nenhumfail
retorno de chamada for fornecido - ou seja, não captar ofail
caso de maneira algumaNa verdade, há uma diferença bastante crítica, na medida em que os diferidos do jQuery devem ser implementações do Promises (e o jQuery3.0 realmente tenta trazê-los para as especificações).
A principal diferença entre concluído / então é que
.done()
SEMPRE retorna os mesmos valores Promise / Wrapped com os quais começou, independentemente do que você faz ou do que você retorna..then()
sempre retorna uma NOVA Promessa e você é responsável por controlar o que essa promessa é baseada no que a função que você passou nela retornou.Traduzido do jQuery para o ES2015 Promises nativo,
.done()
é como implementar uma estrutura de "toque" em torno de uma função em uma cadeia Promise, na medida em que, se a cadeia estiver no estado "resolver", passará um valor para uma função .. mas o resultado dessa função NÃO afetará a própria cadeia.Ambos registrarão 5, não 6.
Observe que eu usei o done e doneWrap para fazer o log, não. Isso porque as funções console.log não retornam nada. E o que acontece se você passar uma função que não retorna nada?
Isso registrará:
O que aconteceu? Quando eu usei .then e passei a ela uma função que não retornou nada, seu resultado implícito foi "indefinido" ... o que, é claro, retornou uma promessa [indefinida] para o método seguinte, que foi registrado indefinido. Portanto, o valor original com o qual começamos foi basicamente perdido.
.then()
é, no fundo, uma forma de composição da função: o resultado de cada etapa é usado como argumento para a função na próxima etapa. É por isso que .done é melhor pensado como um "toque" -> na verdade não faz parte da composição, apenas algo que espreita o valor em uma determinada etapa e executa uma função nesse valor, mas na verdade não altera a composição de qualquer maneira.Essa é uma diferença bastante fundamental, e provavelmente existe uma boa razão pela qual o Promises nativo não possui um método .done implementado. Não temos que explicar por que não existe um método .fail, porque isso é ainda mais complicado (a saber, .fail / .catch NÃO são espelhos das funções .done / .then -> do .catch que retornam valores nus. "stay" rejeitado como aqueles que foram passados para .then, eles resolvem!)
fonte
then()
sempre significa que será chamado em qualquer caso. Mas a passagem de parâmetros é diferente em diferentes versões do jQuery.Antes do jQuery 1.8,
then()
é igual adone().fail()
. E todas as funções de retorno de chamada compartilham os mesmos parâmetros.Porém, a partir do jQuery 1.8,
then()
retorna uma nova promessa e, se retornar um valor, será passado para a próxima função de retorno de chamada.Vamos ver o seguinte exemplo:
Antes do jQuery 1.8, a resposta deveria ser
Tudo
result
leva 3. E athen()
função sempre passa o mesmo objeto adiado para a próxima função.Mas a partir do jQuery 1.8, o resultado deve ser:
Como a primeira
then()
função retorna uma nova promessa, e o valor 7 (e este é o único parâmetro que será transmitido) é passado para a próximadone()
, então a segundadone()
gravaçãoresult = 7
. O segundothen()
recebe 7 como valor dea
e assumeundefined
como valor deb
, portanto, o segundothen()
retorna uma nova promessa com o parâmetro NaN e o últimodone()
imprime NaN como resultado.fonte
jQuery.Deferred()
pode receber vários valores, que corretamente passa para o primeiro.then()
.-A pouco estranho embora ... como qualquer seguinte.then()
não pode fazê-lo. (A interface escolhida viareturn
pode retornar apenas um valor.) O nativo do JavascriptPromise
não faz isso. (O que é mais consistente, para ser honesto.)Existe um mapeamento mental muito simples em resposta que foi um pouco difícil de encontrar nas outras respostas:
done
implementatap
como em bluebird Promisesthen
implementathen
como no ES6 Promisesfonte
Use apenas
.then()
Essas são as desvantagens de
.done()
resolve()
chamada (todos os.done()
manipuladores serão executados de forma síncrona)resolve()
pode receber uma exceção de.done()
manipuladores registrados (!).done()
metade mata o diferido:.done()
manipuladores adicionais serão ignorados silenciosamentePensei temporariamente que
.then(oneArgOnly)
sempre exige.catch()
que nenhuma exceção seja silenciosamente ignorada, mas isso não é mais verdade: ounhandledrejection
evento registra.then()
exceções sem tratamento no console (como padrão). Muito razoável! Não há mais motivo para usar.done()
.Prova
O seguinte trecho de código revela que:
.done()
manipuladores serão chamados síncronos no ponto deresolve()
.done()
influênciasresolve()
resolve()
.done()
resolução adicional.then()
não tem nenhum desses problemasunhandledrejection
é parece)Aliás, as exceções de
.done()
não podem ser capturadas corretamente: por causa do padrão síncrono de.done()
, o erro é lançado no ponto de.resolve()
(pode ser o código da biblioteca!) Ou na.done()
chamada que anexa o culpado se o adiado já tiver sido resolvido.fonte
done
não será executado se um feito anterior tiver uma exceção. Mas por que isso seria ignorado silenciosamente, quero dizer que ocorreu uma exceção, por que você diz que é silencioso? 2) Eu desprezo oDeferred
objeto porque sua API está muito mal executada. É muito complexo e confuso. Seu código aqui também não ajuda a provar seu argumento e possui muita complexidade desnecessária para o que você está tentando provar. 3) Por que osdone
índices 2, 4 e 6 são executados antes do 2ºthen
?.then()
serão chamados, exceção (nesses manipuladores) aumentada ou não. Mas.done()
quebra de adição / restante .Há mais uma diferença vital no jQuery 3.0 que pode facilmente levar a comportamentos inesperados e não é mencionado nas respostas anteriores:
Considere o seguinte código:
isto produzirá:
Agora substitua
done()
porthen()
no mesmo snippet:a saída é agora:
Portanto, para adiados resolvidos imediatamente, a função transmitida para
done()
sempre será invocada de maneira síncrona, enquanto qualquer argumento transmitidothen()
é invocado de forma assíncrona.Isso difere das versões anteriores do jQuery, nas quais os dois retornos de chamada são chamados de forma síncrona, conforme mencionado no guia de atualização :
fonte
.done()
encerra a cadeia de promessas, garantindo que nada mais possa anexar outras etapas. Isso significa que a implementação da promessa do jQuery pode gerar qualquer exceção não tratada, já que ninguém pode lidar com isso usando.fail()
.Em termos práticos, se você não planeja anexar mais etapas a uma promessa, deve usá-lo
.done()
. Para mais detalhes, veja por que as promessas precisam ser feitas.fonte
.done()
não tem uma função final. A documentação diz: "Como deferred.done () retorna o objeto adiado, outros métodos do objeto adiado podem ser encadeados a esse, incluindo métodos adicionais .done ()"..fail()
não é mencionado, mas sim, isso também pode ser encadeado.