Es gibt tatsächlich einen ziemlich kritischen Unterschied, insofern als jQuery's Deferreds gemeint sind, eine Implementierungen von Promises (und jQuery3.0 tatsächlich versucht, sie in spec zu bringen).
Der Hauptunterschied zwischen done/then besteht darin, dass
.done()
gibt IMMER die gleichen Versprechen/eingeschlossenen Werte zurück, mit denen es begonnen hat, unabhängig davon, was Sie tun oder was Sie zurückgeben.
.then()
gibt immer ein NEUES Versprechen zurück, und Sie sind dafür verantwortlich zu kontrollieren, was dieses Versprechen ist, basierend auf dem, was die Funktion, die Sie übergeben haben, zurückgegeben hat.
Übersetzt von jQuery in native ES2015 Promises, .done()
ist so etwas wie die Implementierung einer "Tap"-Struktur um eine Funktion in einer Promise-Kette, die, wenn sich die Kette im Zustand "resolve" befindet, einen Wert an eine Funktion übergibt... aber das Ergebnis dieser Funktion wirkt sich NICHT auf die Kette selbst aus.
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));
Diese werden beide mit 5, nicht mit 6 Punkten bewertet.
Beachten Sie, dass ich done und doneWrap für die Protokollierung verwendet habe, nicht .then. Das liegt daran, dass die console.log-Funktionen eigentlich nichts zurückgeben. Und was passiert, wenn Sie .then eine Funktion übergeben, die nichts zurückgibt?
Promise.resolve(5)
.then(doneWrap( x => x + 1))
.then(console.log.bind(console))
.then(console.log.bind(console));
Das wird protokolliert:
5
undefiniert
Was ist passiert? Wenn ich .then verwendete und eine Funktion übergab, die nichts zurückgab, war das implizite Ergebnis "undefined"... was natürlich ein Promise[undefined] an die nächste then-Methode zurückgab, die undefined protokollierte. Der ursprüngliche Wert, mit dem wir begonnen hatten, war also im Grunde verloren.
.then()
ist im Grunde eine Form der Funktionskomposition: Das Ergebnis eines jeden Schritts wird als Argument für die Funktion im nächsten Schritt verwendet. Deshalb kann man sich .done am besten als "Tap" vorstellen -> es ist nicht wirklich Teil der Komposition, sondern nur etwas, das einen Blick auf den Wert bei einem bestimmten Schritt wirft und eine Funktion mit diesem Wert ausführt, aber die Komposition in keiner Weise verändert.
Dies ist ein ziemlich grundlegender Unterschied, und es gibt wahrscheinlich einen guten Grund, warum native Promises nicht selbst eine .done-Methode implementiert haben. Wir müssen gar nicht erst darauf eingehen, warum es keine .fail-Methode gibt, denn das ist noch komplizierter (nämlich sind .fail/.catch KEINE Spiegel von .done/.then -> Funktionen in .catch, die nackte Werte zurückgeben, "bleiben" nicht abgelehnt wie die an .then übergebenen, sie lösen sich auf!)
15 Stimmen
Bitte beachten Sie, dass JQuery 3.0, das im Juni 2016 veröffentlicht wurde, die erste Version war, die mit der Promises/A+ und ES2015 Promises-Spezifikation konform war. Die Implementierung davor hatte Inkompatibilitäten mit dem, was Promises liefern sollten.
0 Stimmen
I aktualisiert meine Antwort mit einer verbesserten Empfehlung, was wann zu verwenden ist.