Was sind die Unterschiede zwischen Zurückgestellt, Versprechen und Zukunft in JavaScript?

300

Was sind die Unterschiede zwischen Aufgeschobenen, Versprechen und Futures?
Gibt es eine allgemein anerkannte Theorie hinter all diesen drei?

Turm
quelle
11
Ich glaube nicht, dass dies etwas mit jQuery zu tun hat ...
BoltClock
11
Lesen Sie dies: msdn.microsoft.com/en-us/scriptjunkie/gg723713
jfriend00
8
Ich habe sie selbst nicht benutzt, aber hier ist ein ziemlich gutes Intro auf Wikipedia en.wikipedia.org/wiki/Futures_and_promises . Obwohl ich den Anwendungsfall nicht richtig verstehe. In einer asynchronen ereignisgesteuerten Sprache wie Javascript. Auf den ersten Blick kann ich nicht sehen, was sie über Rückrufe bieten, abgesehen von vielleicht einer saubereren API. Ich würde es lieben, wenn jemand ein Beispiel für einen Anwendungsfall liefern und zeigen könnte, wie diese Konzepte angewendet werden und warum Rückrufe eine ineffiziente Lösung wären. @duri das hat nichts mit jQuery zu tun. Kann das jQuery-Tag bitte entfernt werden
AshHeskes
2
@ jfriend00 toller Link, sollte wohl in eine Antwort eingearbeitet werden.
Fncomp

Antworten:

97

Angesichts der offensichtlichen Abneigung gegen den Versuch, die Frage des OP zu beantworten. Die wörtliche Antwort lautet: Ein Versprechen ist etwas, das mit anderen Objekten geteilt wird, während ein Aufgeschobenes privat gehalten werden sollte. In erster Linie kann sich ein Aufgeschobener (der im Allgemeinen das Versprechen erweitert) von selbst auflösen, während ein Versprechen dies möglicherweise nicht kann.

Wenn Sie an den Kleinigkeiten interessiert sind, prüfen Sie Promises / A + .


Soweit mir bekannt ist, besteht der übergeordnete Zweck darin, die Klarheit zu verbessern und die Kopplung über eine standardisierte Schnittstelle zu lockern. Siehe vorgeschlagen Lesen von @ jfriend00:

Anstatt Rückrufe direkt an Funktionen weiterzuleiten, was zu eng gekoppelten Schnittstellen führen kann, können durch die Verwendung von Versprechungen Bedenken hinsichtlich synchronem oder asynchronem Code getrennt werden.

Persönlich habe ich das Zurückstellen als besonders nützlich empfunden, wenn es sich beispielsweise um Vorlagen handelt, die mit asynchronen Anforderungen gefüllt sind, Skripte mit Abhängigkeitsnetzwerken lädt und Benutzerfeedback bereitstellt, um Daten auf nicht blockierende Weise zu bilden.

Tatsächlich vergleicht das reine Callback - Formular , etwas zu tun , nachdem Codemirror in JS - Modus Laden asynchron (Entschuldigung, ich habe nicht jQuery in einem verwendet , während ):

/* assume getScript has signature like: function (path, callback, context) 
   and listens to onload && onreadystatechange */
$(function () {
   getScript('path/to/CodeMirror', getJSMode);

   // onreadystate is not reliable for callback args.
   function getJSMode() {
       getScript('path/to/CodeMirror/mode/javascript/javascript.js', 
           ourAwesomeScript);
   };

   function ourAwesomeScript() {
       console.log("CodeMirror is awesome, but I'm too impatient.");
   };
});

Zu den formulierten Versprechungen (nochmals, Entschuldigung, ich bin bei jQuery nicht auf dem neuesten Stand):

/* Assume getScript returns a promise object */
$(function () {
   $.when(
       getScript('path/to/CodeMirror'),
       getScript('path/to/CodeMirror/mode/javascript/javascript.js')
   ).then(function () {
       console.log("CodeMirror is awesome, but I'm too impatient.");
   });
});

Entschuldigung für den Semi-Pseudo-Code, aber ich hoffe, das macht die Kernidee etwas klarer. Grundsätzlich können Sie durch die Rückgabe eines standardisierten Versprechens das Versprechen weitergeben und so eine klarere Gruppierung ermöglichen.

fncomp
quelle
10
Diese Antwort mag zwar nützlich sein, geht jedoch nicht sachlich auf die Frage ein: Sogenannte Deferreds sind je nach Implementierung entweder Futures oder Versprechen.
awdz9nld
@ MartinKällman Du hast recht! Ich hatte das eine Weile nicht mehr wiederholt und ein bisschen gelernt. Ich werde unten eine separate Antwort veröffentlichen, diese jedoch belassen, da die Benutzer anscheinend von dem Anwendungsbeispiel profitiert haben.
Fncomp
@ MartinKällman, überlegte, eine neue Antwort zu schreiben. Ich denke jedoch, dass das OP tatsächlich wissen wollte, wofür Versprechen und Aufgeschobene gedacht sind. Die Antwort auf seine eigentliche Frage wäre ungefähr: "Aufgeschobene können sich selbst auflösen. AFAIK, die Theorie hinter Versprechungen und aufgeschobenen, stammt von [Functional Reactive Programming | haskell.org/haskellwiki/Functional_Reactive_Programming] , einer Technik zum Reduzieren von Rückrufen . "
Fncomp
2
Dies ist einfach völlig falsch und Ihre Beispiele lassen sich genauso einfach mit Rückrufen durchführen. Bei Versprechungen geht es nicht um die Aggregation und Entkopplung von Rückrufen, sondern um die Bereitstellung eines DSL zum Schreiben von asynchronem Code, wie Synchronisierungscode geschrieben wird. Insbesondere fn(callback, errback)ist es nicht enger gekoppelt oder weniger nützlich als fn().then(callback, errback)- aber das ist sowieso ein falscher Weg, Versprechen zu verwenden. Ich hasse besonders das $.whenBeispiel des Frachtkults - es gibt absolut keinen Grund, warum Sie keine $.whenFunktion haben können, die mit Rückrufen funktioniert.
Esailija
Dies beantwortet jedoch nicht die Frage +1, dass ich in der Lage sein könnte zu wissen, was die Rückrufhölle ist.
Bhojendra Rauniyar
146

Diese Antworten, einschließlich der ausgewählten Antwort, eignen sich gut für die konzeptionelle Einführung von Versprechungen, es fehlen jedoch Einzelheiten darüber, was genau die Unterschiede in der Terminologie sind, die sich bei der Verwendung von Bibliotheken ergibt, die sie implementieren (und es gibt wichtige Unterschiede).

Da es sich immer noch um eine sich weiterentwickelnde Spezifikation handelt , stammt die Antwort derzeit aus dem Versuch, sowohl Referenzen (wie Wikipedia ) als auch Implementierungen (wie jQuery ) zu untersuchen:

  • Aufgeschoben : Nie in populären Referenzen beschrieben, 1 2 3 4, aber häufig von Implementierungen als Schiedsrichter für die Lösung von Versprechen (Implementierung und ) verwendet. 5 6 7 resolvereject

    Manchmal sind aufgeschobene auch Versprechen (Implementierung then), 5 6 andere Male wird es als reiner angesehen, wenn die zurückgestellten nur auflösungsfähig sind und der Benutzer gezwungen wird, auf das Versprechen zur Verwendung zuzugreifen . 7 then

  • Versprechen : Das umfassendste Wort für die diskutierte Strategie.

    Ein Proxy-Objekt, das das Ergebnis einer Zielfunktion speichert, deren Synchronizität wir abstrahieren möchten. Außerdem wird eine thenFunktion verfügbar gemacht, die eine andere Zielfunktion akzeptiert und ein neues Versprechen zurückgibt. 2

    Beispiel aus CommonJS :

    > asyncComputeTheAnswerToEverything()
        .then(addTwo)
        .then(printResult);
    44

     

    Immer in populären Referenzen beschrieben, obwohl nie angegeben, auf wessen Verantwortung die Lösung fällt. 1 2 3 4

    Immer in gängigen Implementierungen vorhanden und nie in der Lage, Lösungen zu finden. 5 6 7

  • Zukunft : Ein scheinbar veralteter Begriff, der in einigen populären Referenzen 1 und mindestens einer populären Implementierung 8 zu finden ist, aber anscheinend aus der Diskussion genommen wird, um den Begriff „Versprechen“ 3 zu bevorzugen, und der in populären Einführungen zum Thema nicht immer erwähnt wird. 9

    Mindestens eine Bibliothek verwendet den Begriff jedoch generisch, um Synchronizität und Fehlerbehandlung zu abstrahieren, ohne thenFunktionen bereitzustellen . 10 Es ist unklar, ob das Vermeiden des Begriffs „Versprechen“ beabsichtigt war, aber wahrscheinlich eine gute Wahl, da Versprechen auf „Thenables“ basieren. 2

Verweise

  1. Wikipedia über Versprechen und Zukunft
  2. Versprechen / A + spec
  3. DOM-Standard für Versprechen
  4. DOM Standard verspricht Spec WIP
  5. DOJO Toolkit zurückgestellt
  6. jQuery zurückgestellt
  7. Q.
  8. FutureJS
  9. Funktioneller Javascript-Abschnitt über Versprechen
  10. Futures in AngularJS-Integrationstests

Verschiedene möglicherweise verwirrende Dinge

Woahdae
quelle
5
Um den Begriff "Zukunft" etwas klarer zu gestalten - Futures haben in vielen Programmiersprachen eine lange Geschichte, die bis in die Mitte der 80er Jahre zurückreicht. Und der Begriff ist heute noch weit verbreitet, insbesondere in der JVM. JavaScript scheint sich dafür entschieden zu haben, den Begriff "Versprechen" zu verwenden, um etwas Ähnliches zu bedeuten, wie Java mit "Zukunft" bedeutet. Scala unterteilt das gleiche Konzept in "Zukunft" und "Versprechen", um auf das "Lesen" -Handle und das "Schreiben" -Handle zu verweisen, die JavaScript-Programmierer als Versprechen bezeichnen.
Heather Miller
1
Und natürlich musste sich Microsoft einen eigenen Begriff dafür einfallen lassen, also heißen sie in C #Task
BlueRaja - Danny Pflughoeft
72

Was mich wirklich zum Klicken gebracht hat, war diese Präsentation von Domenic Denicola.

In einem Github-Kern gab er die Beschreibung, die ich am meisten mag, es ist sehr prägnant:

Der Sinn der Versprechen besteht darin, uns die funktionale Zusammensetzung und das Sprudeln von Fehlern in der asynchronen Welt zurückzugeben.

Mit anderen Worten, Versprechen sind eine Möglichkeit, asynchronen Code zu schreiben, der fast so einfach zu schreiben ist, als wäre er synchron .

Betrachten Sie dieses Beispiel mit Versprechungen:

getTweetsFor("domenic") // promise-returning async function
    .then(function (tweets) {
        var shortUrls = parseTweetsForUrls(tweets);
        var mostRecentShortUrl = shortUrls[0];
        return expandUrlUsingTwitterApi(mostRecentShortUrl); // promise-returning async function
    })
    .then(doHttpRequest) // promise-returning async function
    .then(
        function (responseBody) {
            console.log("Most recent link text:", responseBody);
        },
        function (error) {
            console.error("Error with the twitterverse:", error);
        }
    );

Es funktioniert so, als würden Sie diesen synchronen Code schreiben:

try {
    var tweets = getTweetsFor("domenic"); // blocking
    var shortUrls = parseTweetsForUrls(tweets);
    var mostRecentShortUrl = shortUrls[0];
    var responseBody = doHttpRequest(expandUrlUsingTwitterApi(mostRecentShortUrl)); // blocking x 2
    console.log("Most recent link text:", responseBody);
} catch (error) {
    console.error("Error with the twitterverse: ", error);
}

(Wenn dies immer noch kompliziert klingt, schauen Sie sich diese Präsentation an!)

In Bezug auf Zurückgestellt ist es ein Weg .resolve()oder .reject()Versprechen. In der Promises / B- Spezifikation heißt es .defer(). In jQuery ist es $.Deferred().

Bitte beachten Sie, dass meines Wissens die Promise-Implementierung in jQuery zumindest ab jQuery 1.8.2 fehlerhaft ist (siehe das Wesentliche).
Es implementiert angeblich Promises / A thenables , aber Sie erhalten nicht die richtige Fehlerbehandlung, die Sie sollten, in dem Sinne, dass die gesamte "asynchrone Try / Catch" -Funktionalität nicht funktioniert. Das ist schade, denn ein "Try / Catch" mit asynchronem Code ist absolut cool.

Wenn Sie Promises verwenden werden (Sie sollten sie mit Ihrem eigenen Code ausprobieren!), Verwenden Sie Kris Kowal des Q . Die jQuery-Version ist nur ein Callback-Aggregator zum Schreiben von sauberem jQuery-Code, verfehlt jedoch den Punkt.

In Bezug auf die Zukunft habe ich keine Ahnung, das habe ich in keiner API gesehen.

Bearbeiten: Domenic Denicolas Youtube-Vortrag über Versprechen aus dem Kommentar von @Farm unten.

Ein Zitat von Michael Jackson (ja, Michael Jackson ) aus dem Video:

Ich möchte, dass Sie diesen Satz in Ihrem Kopf verbrennen: Ein Versprechen ist ein asynchroner Wert .

Dies ist eine hervorragende Beschreibung: Ein Versprechen ist wie eine Variable aus der Zukunft - ein erstklassiger Verweis auf etwas, das irgendwann existieren wird (oder passieren wird).

Camilo Martin
quelle
5
Eine großartige Erklärung von Futures (jetzt im DOM implementiert!) Von einem Mitglied des W3-
oligofren
1
@oligofren Danke für den Link, das scheint schön! Übrigens, was für ein mysteriös nerviges Favicon lol.
Camilo Martin
1
Diese Antwort braucht viel mehr positive Stimmen. Es sollte höher gewählt werden als die akzeptierte Antwort IMO.
Chev
1
Domenic Denicolas Youtube-Vortrag über Versprechen: youtube.com/watch?v=hf1T_AONQJU
Farm
@ Farm Großartig! Ich werde das der Antwort hinzufügen.
Camilo Martin
32

Ein Versprechen stellt einen Proxy für einen Wert dar, der bei der Erstellung des Versprechens nicht unbedingt bekannt ist. Sie können Handler dem möglichen Erfolgswert oder dem Fehlergrund einer asynchronen Aktion zuordnen. Auf diese Weise können asynchrone Methoden Werte wie synchrone Methoden zurückgeben: Anstelle des endgültigen Werts gibt die asynchrone Methode das Versprechen zurück, irgendwann in der Zukunft einen Wert zu haben.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Die deferred.promise()Methode ermöglicht eine asynchrone Funktion, um zu verhindern, dass anderer Code den Fortschritt oder den Status seiner internen Anforderung stört. Das Versprechen macht nur die verzögerten Methoden verfügbar, die erforderlich sind, um zusätzliche Handler anzuhängen oder den Status zu bestimmen ( dann erledigt, fehlgeschlagen, immer, Pipe, Fortschritt, Status und Versprechen ), nicht jedoch diejenigen, die den Status ändern ( auflösen, ablehnen, benachrichtigen, auflösen mit). ablehnen mit und benachrichtigen mit ).

Wenn ein Ziel angegeben ist, deferred.promise()hängen die Methoden daran an und geben dieses Objekt zurück, anstatt ein neues zu erstellen. Dies kann nützlich sein, um das Promise-Verhalten an ein bereits vorhandenes Objekt anzuhängen.

Wenn Sie ein Zurückgestelltes erstellen, behalten Sie einen Verweis auf das Zurückgestellte bei, damit es irgendwann aufgelöst oder abgelehnt werden kann. Geben Sie nur das Promise-Objekt über deferred.promise () zurück, damit anderer Code Rückrufe registrieren oder den aktuellen Status überprüfen kann.

Wir können einfach sagen, dass ein Versprechen einen Wert darstellt, der noch nicht bekannt ist, während ein Aufgeschobener eine Arbeit darstellt, die noch nicht abgeschlossen ist.


Geben Sie hier die Bildbeschreibung ein

IRSHAD
quelle
1
plus 1 für die Diagrammdarstellung. Bravisimo !! ^ _ ^
Ashok MA