521 Stimmen

jQuery Deferreds und Versprechen - .then() vs .done()

Ich habe über jQuery deferreds und Versprechen gelesen und ich kann nicht sehen, den Unterschied zwischen mit .then() & .done() für erfolgreiche Rückrufe. Ich weiß Eric Hynds erwähnt, dass .done() y .success() auf dieselbe Funktionalität abbilden, aber ich vermute, dass dies auch für .then() da alle Rückrufe bei Abschluss eines erfolgreichen Vorgangs aufgerufen werden.

Kann mich bitte jemand über die korrekte Verwendung aufklären?

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.

8voto

JasmineOT Punkte 1880

then() bedeutet immer, dass es in jedem Fall aufgerufen wird. Aber die Parameter, die übergeben werden, sind in verschiedenen jQuery-Versionen unterschiedlich.

Vor jQuery 1.8, then() ist gleich done().fail() . Und alle Callback-Funktionen haben die gleichen Parameter.

Aber ab jQuery 1.8, then() gibt ein neues Versprechen zurück, und wenn es einen Wert zurückgegeben hat, wird dieser an die nächste Callback-Funktion übergeben.

Sehen wir uns das folgende Beispiel an:

var defer = jQuery.Deferred();

defer.done(function(a, b){
            return a + b;
}).done(function( result ) {
            console.log("result = " + result);
}).then(function( a, b ) {
            return a + b;
}).done(function( result ) {
            console.log("result = " + result);
}).then(function( a, b ) {
            return a + b;
}).done(function( result ) {
            console.log("result = " + result);
});

defer.resolve( 3, 4 );

Vor jQuery 1.8 sollte die Antwort lauten

result = 3
result = 3
result = 3

Alle result nimmt 3. Und then() Funktion übergibt immer dasselbe deferred object an die nächste Funktion.

Aber ab jQuery 1.8 sollte das Ergebnis sein:

result = 3
result = 7
result = NaN

Weil die erste then() Funktion gibt ein neues Versprechen zurück, und der Wert 7 (und dies ist der einzige Parameter, der weitergegeben wird) wird an die nächste done() so dass die zweite done() schreiben. result = 7 . Die zweite then() nimmt 7 als Wert von a und nimmt undefined als den Wert von b so dass die zweite then() gibt ein neues Versprechen mit dem Parameter NaN zurück, und die letzte done() gibt NaN als Ergebnis aus.

0 Stimmen

"then() bedeutet immer, dass es in jedem Fall aufgerufen wird" -- nicht wahr. then() wird nie im Fehlerfall innerhalb des Promise aufgerufen.

0 Stimmen

Interessanter Aspekt, dass ein jQuery.Deferred() kann mehrere Werte empfangen, die es ordnungsgemäß an den ersten Wert weitergibt .then() Ein bisschen seltsam ist es schon... wie alle folgenden .then() nicht tun können. (Die gewählte Schnittstelle über return kann nur einen Wert zurückgeben). Javascript's native Promise tut das nicht. (Was, um ehrlich zu sein, konsequenter ist.)

5voto

Robert Siemer Punkte 28819

Verwenden Sie nur .then()

Dies sind die Nachteile von .done()

  • kann nicht verkettet werden
  • Block resolve() aufrufen (alle .done() Handler werden synchron ausgeführt)
  • resolve() könnte eine Ausnahme von registrierten .done() Handler(!)
  • eine Ausnahme in einer .done() tötet den Aufgeschobenen halb:
    • weiter .done() werden die Handler stillschweigend übersprungen

Ich dachte vorübergehend, dass .then(oneArgOnly) erfordert immer .catch() damit keine Ausnahme stillschweigend ignoriert wird, aber das ist nicht mehr wahr: die unhandledrejection unbehandelte Ereignisprotokolle .then() Ausnahmen auf der Konsole (als Standard). Sehr vernünftig! Kein Grund mehr für die Verwendung von .done() überhaupt nicht.

Proof

Der folgende Codeschnipsel zeigt, dass:

  • alle .done() Handler werden synchron zum Zeitpunkt der resolve()
    • protokolliert als 1, 3, 5, 7
    • protokolliert, bevor das Skript unten durchfällt
  • Ausnahme in einer .done() beeinflusst resolve() Anrufer
    • protokolliert über Catch Around resolve()
  • Ausnahme bricht Versprechen von weiteren .done() Entschließung
    • 8 und 10 werden nicht protokolliert!
  • .then() hat keines dieser Probleme
    • protokolliert als 2, 4, 6, 9, 11 nach Fadenumdrehungen im Leerlauf
    • (Snippet-Umgebung hat keine unhandledrejection ist scheint)

Übrigens, Ausnahmen von .done() nicht richtig abgefangen werden kann: wegen des synchronen Musters der .done() wird der Fehler entweder an der Stelle ausgelöst, an der .resolve() (könnte Bibliothekscode sein!) oder in der .done() Aufruf, der den Schuldigen festsetzt, wenn der Aufschub bereits aufgelöst ist.

console.log('Start of script.');
let deferred = $.Deferred();
// deferred.resolve('Redemption.');
deferred.fail(() => console.log('fail()'));
deferred.catch(()=> console.log('catch()'));
deferred.done(() => console.log('1-done()'));
deferred.then(() => console.log('2-then()'));
deferred.done(() => console.log('3-done()'));
deferred.then(() =>{console.log('4-then()-throw');
    throw 'thrown from 4-then()';});
deferred.done(() => console.log('5-done()'));
deferred.then(() => console.log('6-then()'));
deferred.done(() =>{console.log('7-done()-throw');
    throw 'thrown from 7-done()';});
deferred.done(() => console.log('8-done()'));
deferred.then(() => console.log('9-then()'));

console.log('Resolving.');
try {
    deferred.resolve('Solution.');
} catch(e) {
    console.log(`Caught exception from handler
        in resolve():`, e);
}
deferred.done(() => console.log('10-done()'));
deferred.then(() => console.log('11-then()'));
console.log('End of script.');

<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh"
crossorigin="anonymous"
></script>

0 Stimmen

Ein paar Dinge: 1) Ich verstehe, was Sie damit sagen wollen. done wird nicht ausgeführt, wenn bei einem vorhergehenden Vorgang eine Ausnahme aufgetreten ist. Aber warum sollte es stillschweigend ignoriert werden, ich meine eine Ausnahme aufgetreten ist, warum sagen Sie, es ist still. 2) Ich verachte die Deferred Objekt, weil seine API sehr, sehr schlecht gemacht ist. Sie ist zu komplex und verwirrend. Ihr Code hier hilft auch nicht, Ihren Standpunkt zu beweisen, und er hat zu viel unnötige Komplexität für das, was Sie zu beweisen versuchen. 3) Warum sind die done bei Index 2, 4 und 6 vor der 2. then ?

0 Stimmen

Mein Fehler, du hast auf jeden Fall eine Stimme verdient. Wie für Ihren Kommentar über die Ausnahme, normalerweise ist das, wie Ausnahmen arbeiten: einmal ausgelöst, Code nach es wird nicht ausgeführt werden. Plus die jQuery-Dokumentation besagt, dass es nur ausgeführt werden, wenn die latente aufgelöst wird.

0 Stimmen

@CodingYoshi Die Situation ist hier anders: Ich habe nur über aufgelöste Promises/Deferreds gesprochen. Ich beschwere mich nicht, dass der Rest des Success-Handlers nicht aufgerufen wird, das ist normal. Aber ich sehe keinen Grund, warum ein komplett anderer Success-Handler bei einem erfolgreichen Versprechen nicht aufgerufen wird. Alle .then() aufgerufen werden, egal ob eine Ausnahme (in diesen Handlern) ausgelöst wird oder nicht. Aber Hinzufügung/Verbleib .done() Pause.

4voto

schellmax Punkte 5344

Es gibt noch einen weiteren entscheidenden Unterschied, und zwar jQuery 3.0 die leicht zu unerwartetem Verhalten führen kann und in früheren Antworten nicht erwähnt wurde:

Betrachten Sie den folgenden Code:

let d = $.Deferred();
d.done(() => console.log('then'));
d.resolve();
console.log('now');

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>

wird dies ausgegeben:

then
now

Ersetzen Sie nun done() von then() in demselben Ausschnitt:

var d = $.Deferred();
d.then(() => console.log('then'));
d.resolve();
console.log('now');

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>

Ausgabe ist jetzt:

now
then

Bei sofort aufgelösten Deferreds wird die Funktion, die an done() wird immer auf synchrone Weise aufgerufen, während jedes Argument, das an then() asynchron aufgerufen wird.

Dies unterscheidet sich von früheren jQuery-Versionen, wo beide Callbacks synchron aufgerufen werden, wie in der Upgrade-Leitfaden :

Eine weitere Verhaltensänderung, die für die Einhaltung von Promises/A+ erforderlich ist, besteht darin, dass Aufgeschobene .then()-Callbacks werden immer asynchron aufgerufen. Wenn früher ein .then()-Callback zu einem Deferred hinzugefügt wurde, das bereits aufgelöst oder abgelehnt wurde, wurde der Callback sofort und synchron.

0 Stimmen

Ich danke Ihnen. Diese Antwort erklärt das Verhalten, das ich gesehen habe. Ich verwendete then() . Mein Test schlug fehl, weil der Callback asynchron aufgerufen wurde, nachdem der Test beendet war. Verwendung von done() wird der Callback synchron aufgerufen und erfüllt die Testerwartungen, und der Test ist bestanden.

3voto

B M Punkte 3713

Es gibt eine sehr einfache mentale Zuordnung in der Antwort, die in den anderen Antworten etwas schwer zu finden war:

1voto

Stephan van Hoof Punkte 203

Zusätzlich zu den oben genannten Antworten:

Die wahre Stärke von .then ist die Möglichkeit, Ajax-Aufrufe fließend zu verketten und so die Callback-Hölle zu vermeiden.

Zum Beispiel:

$.getJSON( 'dataservice/General', {action:'getSessionUser'} )
    .then( function( user ) {
        console.log( user );
        return $.getJSON( 'dataservice/Address', {action:'getFirstAddress'} );
    })
    .then( function( address ) {
        console.log( address );
    })

Hier folgt das zweite .then auf das zurückgegebene $.getJSON

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X