Na 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.
const doneWrap = fn => x => { fn(x); return x };
Promise.resolve(5)
.then(doneWrap( x => x + 1))
.then(doneWrap(console.log.bind(console)));
$.Deferred().resolve(5)
.done(x => x + 1)
.done(console.log.bind(console));
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?
Promise.resolve(5)
.then(doneWrap( x => x + 1))
.then(console.log.bind(console))
.then(console.log.bind(console));
Isso registrará:
5
Indefinido
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!)