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!)