Was bedeutet die Funktion then () in JavaScript?

275

Ich habe Code gesehen, der aussieht wie:

myObj.doSome("task").then(function(env) {
    // logic
});

Woher kommt then()das?

Kay Pale
quelle
8
AKTUALISIERT: Ich fand heraus, dass es mit den CommonJS-Versprechungen zu tun hat. API sitepen.com/blog/2010/01/19/…
Kay Pale

Antworten:

348

Die traditionelle Art, mit asynchronen Aufrufen in JavaScript umzugehen, waren Rückrufe. Angenommen, wir mussten drei Anrufe nacheinander beim Server tätigen, um unsere Anwendung einzurichten. Bei Rückrufen sieht der Code möglicherweise wie folgt aus (unter der Annahme einer xhrGET-Funktion, um den Server aufzurufen):

// Fetch some server configuration
    xhrGET('/api/server-config', function(config) {
        // Fetch the user information, if he's logged in
        xhrGET('/api/' + config.USER_END_POINT, function(user) {
            // Fetch the items for the user
            xhrGET('/api/' + user.id + '/items', function(items) {
                // Actually display the items here
            });
        });
    });

In diesem Beispiel rufen wir zuerst die Serverkonfiguration ab. Auf dieser Grundlage rufen wir dann Informationen über den aktuellen Benutzer ab und erhalten schließlich die Liste der Elemente für den aktuellen Benutzer. Jeder xhrGET-Aufruf übernimmt eine Rückruffunktion, die ausgeführt wird, wenn der Server antwortet.

Je mehr Verschachtelungsebenen wir haben, desto schwieriger ist es natürlich, den Code zu lesen, zu debuggen, zu warten, zu aktualisieren und im Grunde genommen damit zu arbeiten. Dies ist allgemein als Rückrufhölle bekannt. Wenn wir Fehler behandeln müssen, müssen wir möglicherweise jedem xhrGET-Aufruf eine andere Funktion übergeben, um ihm mitzuteilen, was im Fehlerfall zu tun ist. Wenn wir nur einen gemeinsamen Fehlerbehandler haben wollten, ist das nicht möglich.

Die Promise-API wurde entwickelt, um dieses Verschachtelungsproblem und das Problem der Fehlerbehandlung zu lösen.

Die Promise-API schlägt Folgendes vor:

  1. Jede asynchrone Aufgabe gibt ein promiseObjekt zurück.
  2. Jedes promiseObjekt verfügt über eine thenFunktion, die zwei Argumente annehmen kann, einen success Handler und einen errorHandler.
  3. Der Erfolg oder die Fehlerbehandlungsroutine in der thenFunktion wird nach Abschluss der asynchronen Task nur einmal aufgerufen .
  4. Die thenFunktion gibt auch a zurück promise, um die Verkettung mehrerer Aufrufe zu ermöglichen.
  5. Jeder Handler (Erfolg oder Fehler) kann a zurückgeben value, das argumentin der Kette von promises an die nächste Funktion als a übergeben wird .
  6. Wenn ein Handler a zurückgibt promise(eine weitere asynchrone Anforderung stellt), wird der nächste Handler (Erfolg oder Fehler) erst aufgerufen, nachdem diese Anforderung abgeschlossen wurde.

Der vorherige Beispielcode könnte also unter Verwendung von Versprechungen und des $httpDienstes (in AngularJs) wie folgt übersetzt werden :

$http.get('/api/server-config').then(
    function(configResponse) {
        return $http.get('/api/' + configResponse.data.USER_END_POINT);
    }
).then(
    function(userResponse) {
        return $http.get('/api/' + userResponse.data.id + '/items');
    }
).then(
    function(itemResponse) {
        // Display items here
    }, 
    function(error) {
        // Common error handling
    }
);

Erfolg und Irrtum verbreiten

Das Verketten von Versprechungen ist eine sehr leistungsfähige Technik, mit der wir eine Vielzahl von Funktionen ausführen können, z. B. einen Dienst, der einen Server aufruft, eine Nachbearbeitung der Daten durchführt und die verarbeiteten Daten dann an den Controller zurückgibt. Aber wenn wir mit promiseKetten arbeiten, müssen wir einige Dinge beachten.

Betrachten Sie die folgende hypothetische promiseKette mit drei Versprechungen, P1, P2 und P3. Jeder promisehat einen Erfolgshandler und einen Fehlerhandler, also S1 und E1 für P1, S2 und E2 für P2 und S3 und E3 für P3:

xhrCall()
  .then(S1, E1) //P1
  .then(S2, E2) //P2
  .then(S3, E3) //P3

Im normalen Ablauf, in dem keine Fehler vorliegen, würde die Anwendung S1, S2 und schließlich S3 durchlaufen. Aber im wirklichen Leben sind die Dinge nie so glatt. Bei P1 kann ein Fehler auftreten, oder bei P2 kann ein Fehler auftreten, der E1 oder E2 auslöst.

Betrachten Sie die folgenden Fälle:

• Wir erhalten eine erfolgreiche Antwort vom Server in P1, aber die zurückgegebenen Daten sind nicht korrekt oder es sind keine Daten auf dem Server verfügbar (denken Sie an ein leeres Array). In einem solchen Fall sollte für das nächste Versprechen P2 der Fehlerbehandler E2 ausgelöst werden.

• Wir erhalten einen Fehler für das Versprechen P2, der E2 auslöst. Im Handler befinden sich jedoch Daten aus dem Cache, die sicherstellen, dass die Anwendung wie gewohnt geladen werden kann. In diesem Fall möchten wir möglicherweise sicherstellen, dass nach E2 S3 aufgerufen wird.

Jedes Mal, wenn wir einen Erfolgs- oder Fehlerhandler schreiben, müssen wir einen Anruf tätigen. Ist dieses Versprechen angesichts unserer aktuellen Funktion ein Erfolg oder ein Misserfolg für den nächsten Handler in der Versprechenskette?

Wenn wir den Erfolgshandler für das nächste Versprechen in der Kette auslösen möchten, können wir einfach einen Wert aus dem Erfolgs- oder dem Fehlerhandler zurückgeben

Wenn wir andererseits den Fehlerbehandler für das nächste Versprechen in der Kette auslösen möchten, können wir dies mithilfe eines deferredObjekts und Aufrufen seiner reject()Methode tun

Was ist nun ein zurückgestelltes Objekt?

Zurückgestellte Objekte in jQuery stellen eine Arbeitseinheit dar, die später ausgeführt wird, normalerweise asynchron. Sobald die Arbeitseinheit abgeschlossen ist, kann das deferredObjekt auf aufgelöst oder fehlgeschlagen gesetzt werden.

Ein deferredObjekt enthält ein promiseObjekt. Über das promiseObjekt können Sie festlegen, was nach Abschluss der Arbeitseinheit geschehen soll. Sie tun dies, indem Sie Rückruffunktionen für das promiseObjekt festlegen .

Zurückgestellte Objekte in Jquery: https://api.jquery.com/jquery.deferred/

Zurückgestellte Objekte in AngularJs: https://docs.angularjs.org/api/ng/service/ $ q

Sid
quelle
3
Sehr gut geschrieben. Dies hat mir geholfen, Versprechen wirklich festzuhalten.
Ju66ernaut
Ist der Fehlerbehandler, der zweite Parameter, immer optional?
1,21 Gigawatt
Dies ist bei weitem die beste Antwort, die ich bisher gesehen habe!
Imam Bux
78

Die Funktion then () bezieht sich auf "Javascript-Versprechen", die in einigen Bibliotheken oder Frameworks wie jQuery oder AngularJS verwendet werden.

Ein Versprechen ist ein Muster für die Behandlung asynchroner Operationen. Mit dem Versprechen können Sie eine Methode namens "then" aufrufen, mit der Sie die Funktion (en) angeben können, die als Rückruf verwendet werden sollen.

Weitere Informationen finden Sie unter: http://wildermuth.com/2013/8/3/JavaScript_Promises

Und für Angular-Versprechen: http://liamkaufman.com/blog/2013/09/09/using-angularjs-promises/

almoraleslopez
quelle
4
Es ist also wie ein Rückruf, der ausgeführt wird, wenn die Aufgabe erledigt ist. Wie ist es anders
Muhammad Umer
3
Die JavaScript-Versprechen im anderen Kommentar lauten : A promise can only succeed or fail once, undIf a promise has succeeded or failed and you later add a success/failure callback, the correct callback will be called
Xiao
Außerdem erklären die Promise-Nuggets , wie man sie benutzt promiseund was damit gemacht wirdcallback
Xiao
Auf der ersten Seite fehlen Codestücke (große weiße Leerzeichen). Die meisten Leute werden daran denken, das Element zu inspizieren und die URLs der Geige darunter zu finden. Diese Nachricht ist für den Rest - Geigen funktionieren immer noch;)
DanteTheSmith
1
@ MuhammadUmer: Lesen Sie diese stackoverflow.com/a/31453579/1350476 (Antwort von Sid)
SharpCoder
32

Meines Wissens gibt es keine eingebaute then()Methode javascript(zum Zeitpunkt dieses Schreibens).

Es scheint, dass alles, was doSome("task")zurückkehrt, eine Methode hat, die aufgerufen wird then.

Wenn Sie das Rückgabeergebnis von doSome()in der Konsole protokollieren , sollten Sie in der Lage sein, die Eigenschaften der zurückgegebenen Daten anzuzeigen.

console.log( myObj.doSome("task") ); // Expand the returned object in the
                                     //   console to see its properties.

UPDATE (Stand ECMAScript6) : -

Die .then()Funktion wurde in reines Javascript aufgenommen.

Aus der Mozilla-Dokumentation hier ,

Die then () -Methode gibt ein Versprechen zurück. Es werden zwei Argumente benötigt: Rückruffunktionen für die Erfolgs- und Misserfolgsfälle des Versprechens.

Das Promise-Objekt ist wiederum definiert als

Das Promise-Objekt wird für verzögerte und asynchrone Berechnungen verwendet. Ein Versprechen stellt eine Operation dar, die noch nicht abgeschlossen ist, aber in Zukunft erwartet wird.

Das heißt, das Promisefungiert als Platzhalter für einen Wert, der noch nicht berechnet wurde, aber in Zukunft aufgelöst werden soll. Die .then()Funktion wird verwendet, um die Funktionen zuzuordnen, die bei der Lösung des Versprechens aufgerufen werden sollen - entweder als Erfolg oder als Misserfolg.

user113716
quelle
12
Damals gab es noch keine eingebauten .then, aber jetzt kommen native Versprechen in ES6: html5rocks.com/de/tutorials/es6/promises
janfoeh
Vielen Dank für diese Antwort. Ich hatte einen coolen Versprechungsrückruf erwartet, aber es stellte sich heraus, dass es sich um eine tatsächliche Funktion namens "dann" handelte, die zurückgegeben wurde.
Spartikus
15

Hier ist eine Sache, die ich mir selbst gemacht habe, um zu klären, wie die Dinge funktionieren. Ich denke, auch andere können dieses konkrete Beispiel nützlich finden:

doit().then(function() { log('Now finally done!') });
log('---- But notice where this ends up!');

// For pedagogical reasons I originally wrote the following doit()-function so that 
// it was clear that it is a promise. That way wasn't really a normal way to do 
// it though, and therefore Slikts edited my answer. I therefore now want to remind 
// you here that the return value of the following function is a promise, because 
// it is an async function (every async function returns a promise). 
async function doit() {
  log('Calling someTimeConsumingThing');
  await someTimeConsumingThing();
  log('Ready with someTimeConsumingThing');
}

function someTimeConsumingThing() {
  return new Promise(function(resolve,reject) {
    setTimeout(resolve, 2000);
  })
}

function log(txt) {
  document.getElementById('msg').innerHTML += txt + '<br>'
}
<div id='msg'></div>

Magnus
quelle
5

Hier ist eine kleine JS_Fiddle.

Dann gibt es einen Methoden-Rückruf-Stack, der verfügbar ist, nachdem ein Versprechen aufgelöst wurde. Er ist Teil einer Bibliothek wie jQuery, aber jetzt ist er in nativem JavaScript verfügbar. Nachfolgend finden Sie eine ausführliche Erläuterung der Funktionsweise

Sie können ein Versprechen in nativem JavaScript ausführen: Genau wie es in jQuery Versprechen gibt, kann jedes Versprechen gestapelt und dann mit Rückrufen zum Auflösen und Ablehnen aufgerufen werden. So können Sie asynchrone Aufrufe verketten.

Ich gabelte und bearbeitete aus MSDN-Dokumenten den Batterieladestatus.

Dadurch wird versucht herauszufinden, ob der Laptop oder das Gerät des Benutzers den Akku auflädt. dann heißt es und du kannst deine Arbeit nach dem Erfolg erledigen.

navigator
    .getBattery()
    .then(function(battery) {
       var charging = battery.charging;
       alert(charging);
    })
    .then(function(){alert("YeoMan : SINGH is King !!");});

Ein weiteres es6-Beispiel

function fetchAsync (url, timeout, onData, onError) {
    
}
let fetchPromised = (url, timeout) => {
    return new Promise((resolve, reject) => {
        fetchAsync(url, timeout, resolve, reject)
    })
}
Promise.all([
    fetchPromised("http://backend/foo.txt", 500),
    fetchPromised("http://backend/bar.txt", 500),
    fetchPromised("http://backend/baz.txt", 500)
]).then((data) => {
    let [ foo, bar, baz ] = data
    console.log(`success: foo=${foo} bar=${bar} baz=${baz}`)
}, (err) => {
    console.log(`error: ${err}`)
})

Definition :: then ist eine Methode zum Lösen von asynchronen Rückrufen

Dies wird in ES6 eingeführt

Die richtige Dokumentation finden Sie hier. Es6 Promises

Tarandeep Singh
quelle
Ihre Antwort beantwortet die Frage nicht wirklich. Es enthält nur ein Beispiel für die API-Verwendung, ohne zu erläutern, woher es thenkommt und wie es funktioniert. Sie sollten Ihre Antwort verbessern, um diese Details bereitzustellen.
Didier L
@TarandeepSingh - In der ersten Anweisung, in der Sie den Batteriestatus benachrichtigen, wird kein Versprechungsobjekt zurückgegeben. Was nützt dann der zweite
Mohit Jain
@MohitJain Es zeigt, dass Sie mehrere Rückrufe durchführen können, auch wenn Sie kein neues Versprechen haben. Da könnten die Mehrfachanrufe auch mit Promise.all erfolgen.
Tarandeep Singh
WTH meinst du mit " Method Callback Stack "?
Bergi
4

Ich vermute, doSome gibt dies zurück, das ist myObj, das auch eine then-Methode hat. Standardmethode Verkettung ...

Wenn doSome dies nicht zurückgibt und das Objekt ist, auf dem doSome ausgeführt wurde, können Sie sicher sein, dass es ein Objekt mit einer then-Methode zurückgibt ...

Wie @patrick betont, gibt es kein then () für Standard-js

hvgotcodes
quelle
1
Ich vermute, dass doSome dies zurückgibt - nichts erzwingt / rechtfertigt solche Verdächtigungen
Salathiel Genèse
1

doSome ("task") muss ein Versprechen-Objekt zurückgeben, und dieses Versprechen hat immer eine then-Funktion. Ihr Code ist also genau so

promise.then(function(env) {
    // logic
}); 

und Sie wissen, dass dies nur ein gewöhnlicher Aufruf der Mitgliedsfunktion ist.

Hardeep SINGH
quelle
1

.then gibt ein Versprechen in der asynchronen Funktion zurück.

Gutes Beispiel wäre:

var doSome = new Promise(function(resolve, reject){
    resolve('I am doing something');
});

doSome.then(function(value){
    console.log(value);
});

Um eine weitere Logik hinzuzufügen, können Sie dem reject('I am the rejected param')Aufruf auch die Funktion hinzufügen und console.log it.

Appdesigns
quelle
0

In diesem Fall then()handelt es sich um eine Klassenmethode des von doSome()method zurückgegebenen Objekts .


quelle
0

Die Funktion ".then ()" wird häufig für versprochene Objekte in der Asynchoronus-Programmierung für Windows 8 Store-Apps verwendet. Soweit ich verstanden habe, funktioniert es irgendwie wie ein Rückruf.

Details finden Sie in dieser Dokumentation unter http://msdn.microsoft.com/en-us/library/windows/apps/hh700330.aspx

Natürlich kann es auch der Name für eine andere definierte Funktion sein.

user2508620
quelle
-1

Ein anderes Beispiel:

new Promise(function(ok) {
   ok( 
      /* myFunc1(param1, param2, ..) */
   )
}).then(function(){
     /* myFunc1 succeed */
     /* Launch something else */
     /* console.log(whateverparam1) */
     /* myFunc2(whateverparam1, otherparam, ..) */
}).then(function(){
     /* myFunc2 succeed */
     /* Launch something else */
     /* myFunc3(whatever38, ..) */
})

Dieselbe Logik mit Pfeilfunktionen Kurzform:

new Promise((ok) =>
   ok( 
      /* myFunc1(param1, param2, ..) */
)).then(() =>
     /* myFunc1 succeed */
     /* Launch something else */
     /* Only ONE call or statment can be made inside arrow functions */
     /* For example, using console.log here will break everything */
     /* myFunc2(whateverparam1, otherparam, ..) */
).then(() =>
     /* myFunc2 succeed */
     /* Launch something else */
     /* Only ONE call or statment can be made inside arrow functions */
     /* For example, using console.log here will break everything */
     /* myFunc3(whatever38, ..) */
)

NVRM
quelle
-4

Ich bin ungefähr 8 Jahre zu spät, na ja ... sowieso weiß ich nicht wirklich, was dann () tut, aber vielleicht hat MDN eine Antwort. Eigentlich könnte ich es ein bisschen besser verstehen.

Dies zeigt Ihnen (hoffentlich) alle Informationen, die Sie benötigen. Es sei denn, jemand hat diesen Link bereits gepostet. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

Das Format ist versprechen.prototype.then () Das Versprechen und der Prototyp sind wie Variablen, aber nicht wie Variablen in Javascript. Ich meine, wie andere Dinge wie navigator.getBattery (). Then () dorthin gehen, wo diese tatsächlich existiert, aber ist Dieser wird im Internet kaum verwendet und zeigt Statusinformationen zum Akku des Geräts, weitere Informationen und mehr zu MDN, wenn Sie neugierig sind.

Jonathan J. Pecany
quelle