Vorwort
Das erste Mal, als ich mit Versprechen in Kontakt kam, war Microsoft 2012 das Windows 8 -Betriebssystem und untersuchte HTML5, um Metro -Anwendungen mit einer merkwürdigen Einstellung zu schreiben. Zu dieser Zeit waren die asynchronen Schnittstellen in der Winjs -Bibliothek, die mit HTML5 versehen war, alle in Versprechensform, was für mich einfach ein Buch des Himmels war, das gerade JavaScript zu dieser Zeit abgeschlossen hatte. Was ich damals dachte, war, dass Microsoft wieder daran bastelte.
Unerwartet wurde Versprechen bis 2015 tatsächlich in den ES6 -Standard geschrieben. Darüber hinaus zeigt eine Umfrage, dass JS -Programmierer dieses Ding ziemlich hoch verwenden.
Ironischerweise hat Microsoft, das bereits 2012 in der Metro -Anwendungs -Entwicklungsschnittstelle ein Versprechen einsetzte, ein eigener Browser, dh das Versprechen noch erst im Jahr 2015 unterstützt. . .
Wenn man jetzt zurückblickte, war das mühsamste, zu dieser Zeit Versprechen zu sehen, war, dass Anfänger unglaublich erscheinen und auch die am weitesten verbreitete Funktion von JS -Programmierern ist: dann Funktion Call -Kette.
Die Funktionsaufrufkette ist im Wesentlichen im Wesentlichen mehrere asynchrone Prozesse nacheinander aufzurufen. Dieser Artikel beginnt von diesem Punkt und studiert und lernt das Merkmal des Versprechens.
Versprechen gelöst
Betrachten Sie das folgende Szenario, nachdem sich die Funktion um 2 Sekunden um 2 Sekunden verzögert, dann eine Protokollzeile, dann um 3 Sekunden verzögert und dann um 4 Sekunden verzögert und eine Protokollzeile ausdrucken. Dies ist eine sehr einfache Sache in anderen Programmiersprachen, aber es ist schwieriger, in JS einzusteigen, und der Code wird wahrscheinlich wie folgt geschrieben:
var myfunc = function () {setTimeout (function () {console.log ("log1"); setTimeout (function () {console.log ("log2"); setTimeout (function () {console.log ("log3");}, 4000);}, 3000);}, 2000);};Aufgrund der verschachtelten Mehrschicht-Rückrufstruktur wird hier eine typische Pyramidenstruktur gebildet. Wenn die Geschäftslogik komplizierter ist, wird sie zu einer schrecklichen Rückrufhölle.
Wenn Sie ein besseres Bewusstsein haben und wissen, wie man einfache Funktionen extrahiert, sieht der Code so aus:
var func1 = function () {setTimeout (func2, 2000);}; var func2 = function () {console.log ("log1"); setTimeout (func3, 3000);}; var func3 = function () {console.log ("log2"); setTimeout (func4, 4000);}; var func4 = function () {console.log ("log3");};Das sieht ein bisschen besser aus, aber es fühlt sich immer etwas komisch an. . . Nun, mein JS -Level ist begrenzt, daher kann ich nicht sagen, warum ich das nicht gut schreiben kann. Wenn Sie wissen, warum dies nicht gut ist und Sie das Versprechen erfunden haben, lassen Sie es mich bitte wissen.
Kommen wir nun wieder auf den Punkt und sprechen wir über das Versprechen.
Beschreibung des Versprechens
Bitte erlauben Sie mir, hier die Beschreibung des Versprechens von MDN zu zitieren:
Das Versprechensobjekt wird für aufgeschobene Berechnungen und asynchrone Berechnungen verwendet. Ein Versprechensobjekt stellt eine Operation dar, die nicht abgeschlossen wurde, die voraussichtlich in Zukunft abgeschlossen sein wird.
Das Versprechensobjekt ist ein Proxy für den Rückgabewert, der möglicherweise nicht bekannt ist, wenn das Versprechensobjekt erstellt wird. Sie können eine Handhabungsmethode zum Erfolg oder Misserfolg einer asynchronen Operation angeben. Dies ermöglicht es einer asynchronen Methode, einen Wert wie eine synchrone Methode zurückzugeben: Die asynchrone Methode gibt ein Versprechen -Objekt zurück, das den ursprünglichen Rückgabewert anstelle des ursprünglichen Rückgabewerts enthält.
Das Versprechensobjekt hat die folgenden Zustände:
• Ausstehend: Anfangszustand, nicht erfüllt oder abgelehnt.
• Erfüllt: erfolgreicher Betrieb.
• Abgelehnt: Fehlgeschlagen.
Das Versprechensobjekt mit einem ausstehenden Zustand kann mit einem Erfolgswert oder einem abgelehnten Zustand mit einer Fehlermeldung in einen erfüllten Zustand umgewandelt werden. Wenn der Zustand übergeht, wird die Methode, die an Versprechen gebunden ist. Dann wird (Funktionshandle) aufgerufen. (Beim Bindung einer Methode wird die entsprechende Methode sofort aufgerufen, wenn sich das Versprechungsobjekt bereits im erfüllten oder abgelehnten Zustand befindet, sodass zwischen dem Abschluss der asynchronen Operation und ihrer Bindungsmethode keine Rassenbedingung besteht.)
Weitere Beschreibungen und Beispiele für Versprechen finden Sie in der Versprechenseintragung von MDN oder dem Versprecheneintrag von MSDN.
Versuchen Sie, unser Problem mit Versprechen zu lösen
Basierend auf dem obigen Verständnis des Versprechens wissen wir, dass wir es verwenden können, um das Problem zu lösen, dass der Code hinter verschachtelten mehrschichtigen Rückernständen dumm und schwer zu pflegen ist. Die beiden oben angegebenen Links sind bereits sehr klar über die Syntax und die Parameter des Versprechens. Ich werde sie hier nicht wiederholen, sondern den Code einfach hochladen.
Versuchen wir zunächst einen relativ einfachen Fall, der nur einmal Verzögerungen und Rückrufe ausführt:
New Promise (Funktion (res, rej) {console.log (date.now () + "start setTimeout"); setTimeout (res, 2000);}). Dann (function () {console.log (Datum.Now () + "Timeout Call Back");});Es scheint, dass es keinen Unterschied zu den Beispielen in MSDN gibt, und das Ausführungsergebnis lautet wie folgt:
$ node promistest.js1450194136374 Start SetTimeout1450194138391 Timeout -Rückruf
Wenn wir also eine weitere Verzögerung durchführen wollen, kann ich Folgendes schreiben:
New Promise (Funktion (res, rej) {console.log (Datum.Now () + "start setTimeout 1"); setTimeout (res, 2000);}). Dann (function () {console.log (Datum.Now () + "Timeout 1 Call Back"); New Promise (Funktion (res, rej). 3000);Es scheint auch richtig zu funktionieren:
$ node promistest.js1450194338710 Start SetTimeout 11450194340720 Timeout 1 Rückruf1450194340720 Start SetTimeout 21450194343722 Timeout 2 Rufen Sie zurück zurück.
Aber der Code sieht dumm und süß aus, oder? Es baut wieder vage eine Pyramide. Dies widerspricht dem Zweck der Einführung von Versprechen.
Was ist das Problem? Was ist die richtige Haltung?
Die Antwort ist im Rückgabewert der damaligen Funktion und der von der dann überfüllten (oder eingeplanten) Rückruffunktion der Funktionen versteckt.
Zunächst gibt die dann die Funktion eine neue Variable für Versprechen zurück, und Sie können die dann die Funktion dieser neuen Versprechensvariablen wie folgt erneut aufrufen:
neues Versprechen (...). Dann (...) .then (...). Dann (...). Dann (...). Dann (...).
Welche Art von Promenen durch die damalige Funktion zurückgegeben wird, hängt vom Rückgabewert des unerfüllten Rückrufs ab.
In der Tat kann ONFADELLED eine normale Variable oder eine andere Variable für Versprechen zurückgeben.
Wenn die Vereinigung einen Normalwert zurückgibt, gibt die Funktion eine Standard -Variable für Versprechen zurück. Durch die Ausführung der damaligen Funktion dieses Versprechens wird das Versprechen sofort erfüllt, und die überfüllte Funktion wird ausgeführt, und der überfüllte Eintragsparameter ist der Rückgabewert der vorherigen, die nicht erfüllt ist.
Wenn eine Versprechungsvariable eine Versprechensvariable zurückgibt, wird diese Versprechenvariable als Rückgabewert der damaligen Funktion verwendet.
Die Dokumente auf MDN und MSDN haben keine klare positive Beschreibung dieser Reihe von Einstellungen für die damalige Funktion und die überfüllte Funktion. Wie für die offizielle ES6-Dokument-ECMascript 2015 (6. Ausgabe, ECMA-262). . . Ich kann mein Niveau wirklich nicht verstehen. Wenn ein Experte die Beschreibung der beiden Rückgabewerte im offiziellen Dokument erläutern kann, hinterlassen Sie bitte eine Nachricht, um Ratschläge zu erhalten! ! !
Das obige ist also mein freies Spiel, und die Sprachorganisation ist etwas schwer zu beschreiben. Sie werden verstehen, nachdem Sie den Code gelesen haben.
Erstens der Fall der Rückgabe normaler Variablen:
New Promise (Funktion (res, rej) {console.log (Datum.Now () + "Start setTimeout 1"); setTimeout (res, 2000);}). Dann (Funktion () {console.log (Datum.Now () + "Timeout 1 Call zurück"); arg);Das obige Codeausführungsergebnis ist:
$ node promistest.js1450277122125 Start SetTimeout 11450277124129 Timeout 1 RACK BACK1450277124129 Letzte aufgelöste Rückgabe 1024
Es ist ein bisschen interessant, richtig, aber das ist nicht der Schlüssel. Der Schlüssel ist, dass die überfüllte Funktion eine Versprechensvariable zurückgibt, die es uns bequem macht, mehrere asynchrone Prozesse nacheinander aufzurufen. Zum Beispiel können wir versuchen, zwei Verzögerungsvorgänge in Folge durchzuführen:
New Promise (Funktion (res, rej) {console.log (Datum.Now () + "Start setTimeout 1"); setTimeout (res, 2000);}). Dann (Funktion () {console.log (Datum.Now () + "Timeout 1 Call -Back"); Rückgabe neuer Verheißungen (Funktion (reso) (res, rej). 3000);Die Ausführungsergebnisse sind wie folgt:
$ node promistest.js1450277510275 Start SetTimeout 11450277512276 Timeout 1 Rückruf zurück.
Wenn Sie der Meinung sind, dass dies nichts Großartiges ist, ist es kein Problem, es noch ein paar Mal zu tun:
New Promise (Funktion (res, rej) {console.log (Datum.Now () + "Start setTimeout 1"); setTimeout (res, 2000);}). Dann (Funktion () {console.log (Datum.Now () + "Timeout 1 Call -Back"); Rückgabe neuer Verheißungen (Funktion (reso) (res, rej). 3000); "Timeout 3 zurückrufen");$ node promistest.js1450277902714 Start SetTimeout 11450277904722 Timeout 1 Rückruf1450277904724 Start SetTimeout 21450277907725 Timeout 2 Ruf zurück. setTimeout 41450277916744 Timeout 4 RACKT
Es ist ersichtlich, dass mehrere verzögerte Rückruffunktionen ordentlich angeordnet sind und es keine beliebte pyramidenähnliche Struktur gibt. Obwohl der Code asynchrone Prozesse aufruft, sieht es so aus, als würden sie alle aus synchronen Prozessen bestehen. Dies ist das Benefizversprechen.
Wenn Sie die gute Angewohnheit haben, den ausführlichen Code in separate Funktionen zu unterteilen, wird dies noch schöner sein:
Funktion Timeout1 () {Neue Versprechen zurückgeben (Funktion (res, rej) {console.log (Datum.Now () + "Start Timeout1"); timeout3 () {return New Promise (function (res, rej) {console.log (Datum.Now () + "Start Timeout2"); setTimeout (res, 3000);});} Funktion Timeout3 () {return New Promise (function (res, rej) {console.log (date); timeout4 () {return New Promise (function (res, rej) {console.log (Datum.Now () + "Start Timeout4"); setTimeout (res, 5000);});} timeout1 () .then (timeout2) .then (timeout3) .then (Timeout4) .Then (). });$ node promistest.js1450278983342 Start Timeout11450278985343 Start Timeout2145027898351 Timeout31450278992356 START Timeout4145027897370 Timout4 Callback 4
Als nächstes können wir weiterhin das Problem der Übergabe der eingehenden Parameter der überfüllten Funktion untersuchen.
Wir wissen bereits, dass dieser Wert der Eintragsparameter der aufgelösten Funktion ist, wenn die vorherige auf Vollbekämpfung erfüllte Funktion einen Normalwert zurückgibt. Wenn der vorherige erläuterte Variable dann eine Versprechensvariable zurückgibt, woher kommt der Eintragsparameter der erläuterten?
Die Antwort lautet, dass der Eintragsparameter dieser aufgelösten Funktion der Wert ist, in dem die Auflösungsfunktion im vorherigen Versprechen aufgerufen wurde.
Ich konnte den Sprung für eine Weile nicht akzeptieren, oder? Lass es uns gut machen.
Was ist das Funktionsversprechen. Resolve? Verwenden der Anweisung von Zou Zou über MDN
Lösen Sie ein Versprechensobjekt mit dem Erfolgswert. Wenn der Wert kontinuierlich ist (damals, d. H. Mit der damaligen Methode), folgt das zurückgegebene Versprechensobjekt dem Wert "
Kurz gesagt, dies ist der Rückruf, wenn der asynchrone Anruf erfolgreich ist.
Schauen wir uns an, wie der Rückruf in einer normalen asynchronen Schnittstelle aussieht. Nehmen Sie beispielsweise FS.ReadFile (Datei [, Optionen], Callback) auf NodeJs. Das typische Aufrufbeispiel ist wie folgt
fs
Denn für die Fs.ReadFile -Funktion, unabhängig davon, ob er erfolgreich oder fehlgeschlagen ist, wird der Rückruf von Callback -Funktionen aufgerufen, sodass dieser Rückruf zwei Parameter akzeptiert, nämlich die Ausnahmebeschreibung für den Fehler -ERR und die Rückgabeergebnisdaten zum Erfolg.
Wenn wir also Versprechen verwenden, um dieses Beispiel für das Lesen von Dateien zu rekonstruieren, wie sollen wir sie dann schreiben?
Erstens die Funktion fs.Readfile ein.
Funktion ReadFile (Dateiname) {Neue Verheißung zurückgeben (Funktion (Resolve, Rejecting) {fs.ReadFile (Dateiname, Funktion (err, data) {if (err) {reject (err);} else {Resolve (data);}});});});});});};}Der zweite ist der Anruf:
ReadFile ('theFile.txt'). Dann (Funktion (Daten) {console.log (data);}, function (err) {throw err;});Stellen Sie sich vor, der Inhalt der Datei wird normalerweise in der synchronen Anrufschnittstelle von Lesen von Dateien in anderen Sprachen platziert? Ist der Funktionsrückgabewert korrekt? Die Antwort lautet heraus, was ist der Eintragsginseng dieser Entschlossenheit? Es ist der Rückgabewert, wenn der asynchrone Anruf erfolgreich ist.
Mit diesem Konzept ist es nicht schwierig, den "Eingabeparameter der überfüllten Funktion zu verstehen, dass der Wert beim Aufrufen der Auflösungsfunktion im vorherigen Versprechen übergeben wird". Weil die überfüllte Aufgabe darin besteht, das Ergebnis zu verarbeiten, nachdem der vorherige asynchrone Anruf erfolgreich ist.
Leider richtete sich schließlich aus. . .
Zusammenfassen
Bitte erlauben Sie mir, einen Code zu verwenden, um die in diesem Artikel erläuterten wichtigsten Punkte zusammenzufassen:
Funktion CALLP1 () {console.log (Datum.Now () + "start callp1"); Neues Versprechen zurückgeben (Funktion (res, rej) {setTimeout (Res, 2000);}); Return New Promise (Funktion (res, rej) {setTimeout (function () {res ({arg1: 4, arg2: "arg2 value"});}, 3000);}); return New Promise (function (res, rej) {setTimeout (function () {res ("callp3");}, arg * 1000);});} callp1 (). Dann (function () {console.log (Datum.Now () + "CALLP1 Return"); value = " + json.Stringify (ret)); return CALLP3 (ret.arg1);}). Dann (Funktion (ret) {console.log (Datum.Now () +" CALLP3 Return With Ret value = " + ret);}) $ node promistest.js1450191479575 Start CallP11450191481597 CALLP1 Return1450191481599 Start Callp21450191484605 CALLP2 RESVERGROSS MIT RET -VALTE = {"Arg. 41450191488610 CALLP3 Return With Ret Value = CALLP3Die obige einfache Lernerfahrung bei der Verwendung von Versprechen zur Lösung mehrschichtiger asynchroner Anrufe ist der gesamte Inhalt, den ich mit Ihnen teile. Ich hoffe, Sie können Ihnen eine Referenz geben und ich hoffe, Sie können wulin.com mehr unterstützen.