In realtà c'è una differenza piuttosto critica, nella misura in cui i Deferreds di jQuery sono pensati per essere implementazioni di Promises (e jQuery3.0 cerca effettivamente di portarli nelle specifiche).
La differenza chiave tra done / then è quella
.done() Restituisce SEMPRE gli stessi valori di Promessa / a capo con cui è iniziato, indipendentemente da ciò che fai o da ciò che restituisci.
.then() restituisce sempre una NUOVA Promessa e sei responsabile del controllo di ciò che tale Promessa si basa su ciò che la funzione che hai passato lo ha restituito.
Tradotto da jQuery in promesse ES2015 native, .done()è un po 'come implementare una struttura "tap" attorno a una funzione in una catena Promise, in quanto, se la catena è nello stato "risoluzione", passerà un valore a una funzione. ma il risultato di quella funzione NON influenzerà la catena stessa.
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));
Entrambi registreranno 5, non 6.
Si noti che ho usato done e doneWrap per eseguire la registrazione, non .then. Questo perché le funzioni console.log in realtà non restituiscono nulla. E cosa succede se si passa a una funzione che non restituisce nulla?
Promise.resolve(5)
.then(doneWrap( x => x + 1))
.then(console.log.bind(console))
.then(console.log.bind(console));
Questo registrerà:
5
non definito
Quello che è successo? Quando ho usato .then e gli ho passato una funzione che non ha restituito nulla, il risultato implicito è stato "indefinito" ... che ovviamente ha restituito una Promessa [indefinita] al successivo metodo, che ha registrato indefinito. Quindi il valore originale con cui abbiamo iniziato era sostanzialmente perso.
.then()è, in sostanza, una forma di composizione della funzione: il risultato di ogni passaggio viene utilizzato come argomento per la funzione nel passaggio successivo. Ecco perché .done è meglio pensato come un "tap" -> in realtà non fa parte della composizione, solo qualcosa che si intrufola nel dare un'occhiata al valore in un determinato passaggio ed esegue una funzione a quel valore, ma in realtà non cambia la composizione in alcun modo.
Questa è una differenza abbastanza fondamentale, e c'è probabilmente una buona ragione per cui Promise native non hanno implementato un metodo .done. Non dobbiamo mai capire perché non esiste un metodo .fail, perché è ancora più complicato (vale a dire .fail / .catch NON sono i mirror di .done / .then -> funzioni in .catch che restituiscono valori nudi non lo fanno "resta" respinto come quelli passati a .quindi, si risolvono!)