Einführung in Versprechen
Ein Versprechen wird üblicherweise als Proxy für einen Wert definiert, der schließlich verfügbar wird.
Versprechungen sind eine Möglichkeit, mit asynchronem Code umzugehen, ohne in der Callback-Hölle stecken zu bleiben.
Versprechungen sind seit Jahren Teil der Sprache (standardisiert und in ES2015 eingeführt) und wurden in letzter Zeit stärker integriert, mit async und await in ES2017.,
Asynchrone Funktionen verwenden Versprechen hinter den Kulissen, daher ist es wichtig zu verstehen, wie Versprechen funktionieren, um zu verstehen, wie async
und await
funktionieren.
Wie Versprechen funktionieren, kurz
Sobald ein Versprechen aufgerufen wurde, beginnt es in einem ausstehenden Zustand. Dies bedeutet, dass die aufrufende Funktion weiterhin ausgeführt wird, während das Versprechen aussteht, bis es aufgelöst wird, und der aufrufenden Funktion die angeforderten Daten gibt.,
Das erstellte Versprechen endet schließlich in einem aufgelösten Zustand oder in einem abgelehnten Zustand und ruft die entsprechenden Rückruffunktionen auf (übergeben an then
und catch
).
Welche JS-APIs verwenden Versprechen?
Zusätzlich zu Ihrem eigenen Code und Bibliothekscode werden Versprechungen von modernen Standard-Web-APIs verwendet, z. B.:
- die Batterie-API
- die Abruf-API
- Servicemitarbeiter
Es ist unwahrscheinlich, dass Sie in modernem JavaScript keine Versprechungen verwenden.,
Erstellen eines Versprechens
Die Versprechungs-API stellt einen Versprechungskonstruktor bereit, den Sie mit new Promise()
:
initialisieren Wie Sie sehen können, überprüft das Versprechen die globale Konstante done
, und wenn dies zutrifft, wird das Versprechen in einen aufgelösten Zustand versetzt (da der Rückruf resolve
aufgerufen wurde). reject
Der Rückruf wird ausgeführt, wodurch das Versprechen in einen abgelehnten Zustand versetzt wird., (Wenn keine dieser Funktionen im Ausführungspfad aufgerufen wird, bleibt das Versprechen in einem ausstehenden Zustand)
Mit resolve
und reject
können wir dem Aufrufer mitteilen, was der resultierende Versprechungsstatus war und was damit zu tun ist. Im obigen Fall haben wir nur eine Zeichenfolge zurückgegeben, aber es könnte sich auch um ein Objekt handeln, oder null
. Da wir das Versprechen im obigen Snippet erstellt haben, wurde es bereits ausgeführt. Dies ist wichtig, um zu verstehen, was im folgenden Abschnitt über ein Versprechen vor sich geht.,
Ein häufigeres Beispiel, auf das Sie stoßen können, ist eine Technik namens Promisifying. Diese Technik ist eine Möglichkeit, eine klassische JavaScript-Funktion zu verwenden, die einen Rückruf annimmt und ein Versprechen zurückgibt:
In neueren Versionen von Node.js, Sie müssen diese manuelle Konvertierung für einen Großteil der API nicht durchführen. Im util-Modul ist eine promisifying-Funktion verfügbar, die dies für Sie erledigt, da die Funktion, die Sie versprechen, die richtige Signatur hat.,
Konsumieren eines Versprechens
Im letzten Abschnitt haben wir vorgestellt, wie ein Versprechen erstellt wird.
Nun wollen wir sehen, wie das Versprechen verbraucht oder verwendet werden kann.
Das Ausführen von checkIfItsDone()
gibt Funktionen an, die ausgeführt werden sollen, wenn das Versprechen isItDoneYet
aufgelöst wird (im Aufruf then
) oder abgelehnt wird (im Aufruf catch
).
Versprechungen verketten
Ein Versprechen kann an ein anderes Versprechen zurückgegeben werden, wodurch eine Kette von Versprechungen erstellt wird.,
Ein großartiges Beispiel für Verkettungsversprechen ist die Abruf-API, mit der wir eine Ressource abrufen und eine Kette von Versprechen in die Warteschlange stellen können, die beim Abrufen der Ressource ausgeführt werden sollen.
Die Abruf-API ist ein versprechungsbasierter Mechanismus, und der Aufruf von fetch()
entspricht der Definition unseres eigenen Versprechens mit new Promise()
.
Beispiel zum Verketten von Versprechungen
In diesem Beispiel rufen wir fetch()
auf, um eine Liste der TODO-Elemente aus der todos.json
– Datei im Domänenstamm abzurufen, und erstellen eine Kette von Versprechungen.,
Laufen fetch()
gibt eine Antwort, die hat viele Eigenschaften, und in diejenigen, die wir-Referenz:
-
status
ein numerischer Wert, der die HTTP-status-code -
statusText
, eine status-Nachricht, dieOK
wenn die Anfrage gelungen,
response
auch ein json()
Methode gibt ein Versprechen aufgelöst wird, mit dem Inhalt des Körpers verarbeitet und umgewandelt in JSON.,
Angesichts dieser Prämissen passiert Folgendes: Das erste Versprechen in der Kette ist eine von uns definierte Funktion namens status()
, die den Antwortstatus überprüft und wenn es sich nicht um eine Erfolgsantwort handelt (zwischen 200 und 299), lehnt es das Versprechen ab.
Dieser Vorgang führt dazu, dass die Versprechungskette alle aufgelisteten verketteten Versprechungen überspringt und direkt zur catch()
– Anweisung am unteren Rand überspringt, wobei der Request failed
– Text zusammen mit der Fehlermeldung protokolliert wird.,
Wenn dies stattdessen erfolgreich ist, ruft es die von uns definierte Funktion json()
auf. Da das vorherige Versprechen bei Erfolg das response
Objekt response
, erhalten wir es als Eingabe für das zweite Versprechen.
In diesem Fall geben wir die verarbeiteten JSON-Daten zurück, sodass das dritte Versprechen den JSON direkt empfängt:
.then((data) => { console.log('Request succeeded with JSON response', data)})
und wir melden es einfach an der Konsole an.
Fehlerbehandlung
Im Beispiel hatten wir im vorherigen Abschnitt eine catch
, die an die Kette der Versprechungen angehängt wurde.,
Wenn irgendetwas in der Kette von Versprechungen fehlschlägt und einen Fehler auslöst oder das Versprechen ablehnt, geht das Steuerelement zur nächsten catch()
Anweisung entlang der Kette.
Kaskadierende Fehler
Wenn Sie innerhalb der catch()
einen Fehler auslösen, können Sie eine zweite catch()
anhängen, um damit umzugehen, und so weiter.
new Promise((resolve, reject) => { throw new Error('Error')}) .catch(err => { throw new Error('Error') }) .catch(err => { console.error(err) })
Orchestrieren von Versprechungen
Versprechen.,all ()
Wenn Sie verschiedene Versprechungen synchronisieren müssen, hilft Ihnen Promise.all()
, eine Liste von Versprechungen zu definieren und etwas auszuführen, wenn sie alle aufgelöst sind.
Beispiel:
Mit der ES2015-Zuweisungssyntax für die Destrukturierung können Sie auch
Promise.all().then(() => { console.log('Results', res1, res2)})
Sie sind nicht darauf beschränkt, fetch
zu verwenden Natürlich kann jedes Versprechen auf diese Weise verwendet werden.
Versprechen.,race()
Promise.race()
wird ausgeführt, wenn das erste Versprechen, das Sie an es übergeben, aufgelöst wird, und es wird der angehängte Rückruf nur einmal ausgeführt, wobei das Ergebnis des ersten Versprechens aufgelöst wird.,
Beispiel:
Häufige Fehler
Uncaught TypeError: undefined ist kein Versprechen
Wenn Sie den Uncaught TypeError: undefined is not a promise
– Fehler in der Konsole erhalten, stellen Sie sicher, dass Sie new Promise()
anstelle von nur Promise()
UnhandledPromiseRejectionWarning
Dies bedeutet, dass ein Versprechen, das Sie zurückgewiesen haben, jedoch nicht catch
wurde, um den Fehler zu behandeln. Fügen Sie eine catch
nach der beleidigenden then
hinzu, um dies richtig zu handhaben.