Ich habe ein reines JavaScript-Versprechen (integrierte Implementierung oder Poly-Fill):
var promise = new Promise(function (resolve, reject) { /* ... */ });
Aus der Spezifikation kann ein Versprechen eines der folgenden sein:
- "erledigt" und "gelöst"
- "erledigt" und "abgelehnt"
- 'steht aus'
Ich habe einen Anwendungsfall, in dem ich das Versprechen synchron abfragen und Folgendes bestimmen möchte:
Ist das Versprechen erfüllt?
Wenn ja, ist das Versprechen gelöst?
Ich weiß, dass ich #then()
damit planen kann, dass Arbeiten asynchron ausgeführt werden, nachdem der Status "Versprechen" geändert wurde. Ich frage NICHT, wie das geht.
Diese Frage betrifft speziell die synchrone Abfrage des Status eines Versprechens . Wie kann ich das erreichen?
javascript
promise
es6-promise
Scherz
quelle
quelle
var promiseStatus = NEW_PRIVATE("Promise#status");
,PromiseSet
Funktion anSET_PRIVATE(promise, promiseStatus, status);
console.log(Promise.new((resolve, reject) => {})
=>Promise { <pending> }
Antworten:
Für native JavaScript-Versprechen gibt es keine solche synchrone Inspektions-API. Es ist unmöglich, dies mit einheimischen Versprechungen zu tun. Die Spezifikation spezifiziert keine solche Methode.
Userland-Bibliotheken können dies tun. Wenn Sie auf eine bestimmte Engine (wie v8) abzielen und Zugriff auf Plattformcode haben (dh Sie können Code in den Kern schreiben ), können Sie bestimmte Tools (wie private Symbole) verwenden, um dies zu erreichen . Das ist allerdings super spezifisch und nicht im Userland.
quelle
.any
stattdessen sprechen und einen Fehler machen sollen, weil Mark darauf bestand. Zum einenPromise.race([])
ist ein für immer anstehendes Versprechen (und kein Fehler), Sie möchten normalerweise das erste erfolgreiche Versprechen und nicht nur das erste Versprechen. Auf jeden Fall ist das für die gestellte Frage nicht wirklich relevant - OP fragte nach synchroner Inspektion und nicht nach.race
und seinen vielen Mängeln.MakeQueryablePromise(Promise.resolve(3)).isResolved
ist es falsch, aber das Versprechen ist ganz offensichtlich gelöst. Ganz zu schweigen davon, dass in dieser Antwort auch der Begriff "gelöst" und "erfüllt" falsch verwendet wird. Um dies zu erreichen, können Sie einfach.then
selbst einen Handler hinzufügen - was den Punkt der synchronen Inspektion völlig verfehlt.Versprechen-Status-Async macht den Trick. Es ist asynchron, wird jedoch nicht verwendet,
then
um auf die Lösung des Versprechens zu warten.quelle
Nein, keine Synchronisierungs-API, aber hier ist meine Version der Asynchronisierung
promiseState
(mit Hilfe von @Matthijs):quelle
Promise.race([ Promise.resolve(p).then(() => "fulfilled", () => "rejected"), Promise.resolve().then(() => "pending") ]);
Obwohl mir dies sicherer erscheint:const t = {}; return Promise.race([p,t]).then(v => v === t ? "pending" : "fulfilled", () => "rejected")
und vermeidet es, zusätzliche Versprechen zu erstellen, die bestehen bleiben, solange das ursprüngliche p aussteht.Sie können ein Rennen mit Promise.resolve machen.
Es ist nicht synchron, aber es passiert jetzt
Ein kleines Skript zum Testen und Verstehen ihrer Bedeutung von asynchron
Ergebnisse mit Verzögerung (0) (Kommentar während der Verzögerung)
und die Ergebnisse dieses Tests mit Firefox (Chrom halten die Reihenfolge)
versprechenStaat machen .race und .then: Level 2
quelle
'a value that p should not return'
Verwenden Sie stattdessen ein SymbolSymbol
wäre ein eindeutiger Wert, daher müsste man nie raten, welcher "Wert [...] p nicht zurückkehren sollte". Ein Verweis auf ein bestimmtes Objekt würde jedoch genauso gut funktionieren.Sie können einen (hässlichen) Hack in Node.js verwenden, bis eine native Methode angeboten wird:
quelle
Promise.prototype.isPending = function(){ return util.inspect(this).indexOf("<pending>")>-1; }
process.binding('util').getPromiseDetails
Promise.resolve('<pending>')
.Sagen Sie im Knoten undokumentiert intern
process.binding('util').getPromiseDetails(promise)
quelle
Aktualisiert: 2019
Bluebird.js bietet dies an: http://bluebirdjs.com/docs/api/isfulfilled.html
Wenn Sie lieber Ihren eigenen Wrapper erstellen möchten, finden Sie hier einen schönen Blog darüber.
Da JavaScript Single-Threaded ist, ist es schwierig, einen ausreichend häufigen Anwendungsfall zu finden, um dies in die Spezifikation aufzunehmen. Der beste Ort, um zu wissen, ob ein Versprechen gelöst wird, ist .then (). Wenn Sie testen, ob ein Versprechen erfüllt ist, wird eine Abfrageschleife erstellt, die höchstwahrscheinlich in die falsche Richtung weist.
async / await ist ein schönes Konstrukt, wenn Sie asynchronen Code synchron begründen möchten.
Ein weiterer nützlicher Aufruf ist Promise.all ()
Als ich zum ersten Mal nach dieser Antwort griff, war dies der Anwendungsfall, nach dem ich gesucht hatte.
quelle
Auf diese Weise können Sie Ihre Versprechen einpacken
quelle
.then
immer asynchron ausgeführt wird, wird OP, der ein Versprechen in derselben Runde prüfen möchte, hier nicht das richtige Ergebnis erhalten. Hinweis OP fragte speziell nach synchroner Inspektion und erwähnte, dass sie bereits über asynchrone Inspektion Bescheid wissen.Es ist in der Tat ziemlich ärgerlich, dass diese grundlegende Funktionalität fehlt. Wenn Sie node.js verwenden, sind mir zwei Problemumgehungen bekannt, von denen keine sehr hübsch ist. Beide folgenden Snippets implementieren dieselbe API:
Es scheint keine Möglichkeit zu geben, die letzten beiden Versprechenszustände mit beiden Tricks zu unterscheiden.
1. Verwenden Sie die V8-Debug-API
Dies ist der gleiche Trick, der
util.inspect
verwendet wird.2. Führen Sie Mikrotasks synchron aus
Dies vermeidet die Debug-API, hat jedoch eine erschreckende Semantik, da alle ausstehenden Mikrotasks und
process.nextTick
Rückrufe synchron ausgeführt werden. Es hat auch den Nebeneffekt, dass verhindert wird, dass der Fehler "Ablehnung eines nicht behandelten Versprechens" jemals für das geprüfte Versprechen ausgelöst wird.quelle
process._tickCallback
(oder sogar% RunMicrotick) - es wird zufällig Dinge in Ihrem Code brechen. Ich habe verzweifelt versucht, es zum Laufen zu bringen (meistens für gefälschte Timer in asynchronen Funktionen), und es war von der Knotenseite aus nie stabil genug. Ich habe es irgendwie aufgegeben, daran zu arbeiten. Die V8-Debugspiegel-API ist hier völlig angemessen.DeprecationWarning: DebugContext has been deprecated and will be removed in a future version.
:( Sieht aus wie V8 es entfernt hatprocess.binding('util').getPromiseDetails( promise )
Rückgabe[ 0, ]
für ausstehend,[ 1, value ]
erfüllt und[ 2, value ]
abgelehnt.Vorsichtsmaßnahme: Diese Methode verwendet undokumentierte Node.js-Interna und kann ohne Vorwarnung geändert werden.
In Node können Sie mithilfe von den Status eines Versprechens synchron bestimmen
process.binding('util').getPromiseDetails(/* promise */);
.Dies wird zurückkehren:
[0, ]
für anhängige,[1, /* value */]
für erfüllt, oder[2, /* value */]
für abgelehnt.Packen Sie dies in eine Hilfsfunktion:
quelle
jest
(das ist der einzige Ort, an dem ich wirklich interessiert bin). Die Funktion existiert, scheint aber immer zurückzukehrenundefined
. Wie finde ich heraus, was los ist?mocha
. Ich habe esjest
aber nie versucht . Starten Sie möglicherweise eine neue Frage, die hier verlinkt ist, und geben Sie sowohl Ihre Node.js-Version als auch Ihrejest
Version an.Promise
zu testen, die ich nur zum Testen von Dingen verwendet habe, die ausgeführt werden sollten, während aPromise
ansteht, aber ich dachte mir, solange das, was ich geschrieben habe, funktioniert, besteht keine Notwendigkeit, dies zu testen zusätzlich zu dem, was darauf beruht.Sie können eine Variable verwenden, um den Status zu speichern, den Status manuell auf diese Variable festzulegen und diese Variable zu überprüfen.
Dies bedeutet natürlich, dass Sie Zugriff auf den Originalcode des Versprechens haben müssen. Wenn Sie dies nicht tun, können Sie Folgendes tun:
Meine Lösung ist mehr Codierung, aber ich denke, Sie müssten dies wahrscheinlich nicht für jedes Versprechen tun, das Sie verwenden.
quelle
Ab Node.js Version 8 können Sie jetzt das Wise-Inspection- Paket verwenden, um native Versprechen synchron zu überprüfen (ohne gefährliche Hacks).
quelle
Sie können Promise.prototype eine Methode hinzufügen. Es sieht aus wie das:
Bearbeitet: Die erste Lösung funktioniert nicht richtig, wie die meisten Antworten hier. Es wird "ausstehend" zurückgegeben, bis die asynchrone Funktion ".then" aufgerufen wird, was nicht sofort geschieht. (Gleiches gilt für Lösungen mit Promise.race). Meine zweite Lösung löst dieses Problem.
Sie können es für jedes Versprechen verwenden. Zum Beispiel:
Zweite (und richtige) Lösung:
Und benutze es:
Hinweis : In dieser Lösung müssen Sie den Operator "new" nicht verwenden.
quelle
Hier ist eine ausführlichere es6-Version von QueryablePromise, die es ermöglicht, nach der ersten Auflösung zu verketten und zu fangen und die API sofort aufzulösen oder abzulehnen, um die API mit dem nativen Versprechen in Einklang zu halten.
quelle
await
Verwendung der Antwort von @ jib mit idiomatischem Prototyping.Beachten Sie, dass diese asynchrone Funktion "fast" sofort wie eine synchronisierte Funktion ausgeführt wird (oder tatsächlich möglicherweise sofort ausgeführt wird).
quelle
2019:
Wie ich weiß, ist der einfache Weg, dies zu tun
thenable
, ein superdünner Wrapper um Versprechen oder einen asynchronen Job.quelle
Sie können Ihre eigene Unterklasse erstellen
QueryablePromise
, indem Sie beispielsweise von der nativ verfügbarenPromise
Klasse erben , für deren Instanzen einestatus
Eigenschaft verfügbar ist, mit der Sie den Status der Versprechenobjekte synchron abfragen können . Eine Implementierung kann unter oder verweisen zu sehen dies für eine bessere Erklärung.quelle
fetch
, wird es ein einheimisches Versprechen zurückgeben. Wie würde Ihre Klasse dabei helfen?const queryableFetch = new QueryablePromise((resolve, reject) => {fetch(/.../).then((data) => resolve(data)) })
? Oder gibt es ein Problem damit? : /, err => reject(err)
als zweites Argument , sonstthen
werden Fehler nicht korrekt weitergegeben (unter anderem , weil es als Anti-Pattern des Versprechenskonstruktors gilt ). Es ist zwar nicht wirklich synchron (z. B. wird ein bereits gelöstes Versprechen nicht erkannt), aber möglicherweise nützlich in Fällen, in denen Sie den Anrufer nicht kontrollieren und die Antwort sofort benötigt wird.Es gibt noch eine andere elegante und hackige Methode, um zu überprüfen, ob ein Versprechen noch aussteht, indem Sie das gesamte Objekt in einen String konvertieren und es mithilfe von inspect wie folgt überprüfen :
util.inspect(myPromise).includes("pending")
.Getestet auf Node.js 8,9,10,11,12,13
Hier ist ein vollständiges Beispiel
Ergebnis:
quelle
Wenn Sie ES7 Experimental verwenden, können Sie Async verwenden, um das Versprechen, das Sie hören möchten, einfach zu verpacken.
quelle
Ich habe ein kleines npm-Paket mit dem Versprechen-Wert geschrieben, das einen Versprechen-Wrapper mit einer
resolved
Flagge versehen hat:https://www.npmjs.com/package/promise-value
Es gibt auch synchronen Zugriff auf den Versprechungswert (oder Fehler). Dies ändert nicht das Promise-Objekt selbst, sondern folgt dem Wrap, anstatt das Muster zu erweitern.
quelle
Dies ist eine ältere Frage, aber ich habe versucht, etwas Ähnliches zu tun. Ich muss n Arbeiter am Laufen halten. Sie sind in einem Versprechen strukturiert. Ich muss scannen und sehen, ob sie gelöst, abgelehnt oder noch ausstehend sind. Wenn es behoben ist, brauche ich den Wert. Wenn es abgelehnt wird, kann das Problem behoben werden oder steht noch aus. Wenn gelöst oder abgelehnt, muss ich eine andere Aufgabe starten, um weiterzumachen. Ich kann mit Promise.all oder Promise.race keine Möglichkeit finden, dies zu tun, da ich weiterhin Versprechen in einem Array arbeite und keine Möglichkeit finde, sie zu löschen. Also erstelle ich einen Arbeiter, der den Trick macht
Ich benötige eine Versprechen-Generator-Funktion, die ein Versprechen zurückgibt, das bei Bedarf aufgelöst oder abgelehnt wird. Es wird von einer Funktion aufgerufen, die das Framework einrichtet, um zu wissen, was das Versprechen tut.
Im folgenden Code gibt der Generator einfach ein Versprechen zurück, das auf setTimeout basiert.
Hier ist es
doWork gibt ein Objekt zurück, das das Versprechen sowie dessen Status und Rückgabewert enthält.
Der folgende Code führt eine Schleife aus, die den Status testet und neue Worker erstellt, um ihn bei 3 laufenden Workern zu halten.
Getestet in node.js
Übrigens Nicht in dieser Antwort, sondern in anderen zu ähnlichen Themen, ich hasse es, wenn jemand sagt "Sie verstehen nicht" oder "So funktioniert es nicht". Ich gehe im Allgemeinen davon aus, dass der Fragesteller weiß, was er will. Einen besseren Weg vorzuschlagen ist großartig. Eine geduldige Erklärung, wie Versprechen funktionieren, wäre auch gut.
quelle
Ich fand diese Lösung einfach und erlaubte mir, weiterhin native Versprechen zu verwenden, aber nützliche synchrone Prüfungen hinzuzufügen. Ich musste auch nicht eine ganze Versprechensbibliothek einholen.
CAVEAT: Dies funktioniert nur, wenn der aktuelle Ausführungsthread unterbrochen ist, damit die Versprechen ausgeführt werden können, bevor die synchronen Konstrukte überprüft werden. Das macht dies von geringerer Nützlichkeit, als ich ursprünglich gedacht hatte - dennoch nützlich für meinen Anwendungsfall (Danke Benjamin Gruenbaum für den Hinweis)
Von https://ourcodeworld.com/articles/read/317/how-to-check-if-a-javascript-promise-has-been-fulfilled-rejected-or-resolved , basierend auf ihrer Antwort auf Gibt es einen Weg zu Sagen Sie, ob ein ES6-Versprechen erfüllt / abgelehnt / gelöst wurde?
quelle
MakeQueryablePromise(Promise.resolve(3)).isResolved
ist es falsch, aber das Versprechen ist ganz offensichtlich gelöst. Ganz zu schweigen davon, dass in dieser Antwort auch der Begriff "gelöst" und "erfüllt" falsch verwendet wird. Um dies zu erreichen, können Sie einfach.then
selbst einen Handler hinzufügen - was den Punkt der synchronen Inspektion völlig verfehlt.let wrappedPromise = MakeQueryablePromise(Promise.resolve(3)); setTimeout(function() {console.log(wrappedPromise.isFulfilled())}, 1);
Was, solange Sie das tun, funktioniert das gut. Aber Sie müssen diese Tatsache verstehen, damit dies nützlich ist. Ich werde die Beschreibung mit dieser Einschränkung aktualisieren. Ich stimme auch zu, dass die Funktionsbenennung besser / idiomatischer sein könnte.then
das ursprüngliche Versprechen halten und dasselbe erreichen, da es sowieso asynchron ist. Es gibt einen Wegprocess.binding('util').getPromiseDetails
, der zu funktionieren scheint, aber es wird eine private API verwendet