Mam czystą obietnicę JavaScript (wbudowana implementacja lub poly-fill):
var promise = new Promise(function (resolve, reject) { /* ... */ });
Ze specyfikacji obietnica może być jedną z następujących:
- „rozstrzygnięte” i „rozwiązane”
- „rozstrzygnięte” i „odrzucone”
- 'w oczekiwaniu'
Mam przypadek użycia, w którym chcę przesłuchać obietnicę synchronicznie i określić:
czy Obietnica jest spełniona?
jeśli tak, czy obietnica została rozwiązana?
Wiem, że mogę #then()
zaplanować pracę, która ma być wykonywana asynchronicznie po zmianie stanu Promise. NIE pytam, jak to zrobić.
To pytanie dotyczy w szczególności synchronicznego badania stanu obietnicy . Jak mogę to osiągnąć?
javascript
promise
es6-promise
jokeyrhyme
źródło
źródło
var promiseStatus = NEW_PRIVATE("Promise#status");
,PromiseSet
funkcji uSET_PRIVATE(promise, promiseStatus, status);
console.log(Promise.new((resolve, reject) => {})
=>Promise { <pending> }
Odpowiedzi:
Nie istnieje taki synchroniczny interfejs API inspekcji dla natywnych obietnic JavaScript. Nie da się tego zrobić z rodzimymi obietnicami. Specyfikacja nie określa takiej metody.
Biblioteki przestrzeni użytkownika mogą to zrobić, a jeśli celujesz w konkretny silnik (np. V8) i masz dostęp do kodu platformy (to znaczy możesz pisać kod w rdzeniu ), możesz użyć określonych narzędzi (takich jak symbole prywatne), aby to osiągnąć . Jest to jednak bardzo specyficzne i nie dotyczy przestrzeni użytkownika.
źródło
.any
zamiast tego spekulować i popełnić błąd, ponieważ Mark nalegał. Po pierwsze,Promise.race([])
jest wiecznie oczekującą obietnicą (a nie błędem), zazwyczaj potrzebujesz pierwszej pomyślnej obietnicy, a nie tylko pierwszej. Zresztą, to nie jest tak naprawdę istotne dla zadanego pytania - OP zapytał o synchroniczną kontrolę, a nie o.race
i jej liczne niedociągnięcia.MakeQueryablePromise(Promise.resolve(3)).isResolved
jest fałszywa, ale obietnica jest całkiem oczywista. Nie wspominając o tym, że w odpowiedzi niepoprawnie użyto również terminów „rozwiązany” i „spełniony”. Aby to zrobić, wystarczy, że.then
sam dodasz program obsługi - co całkowicie mija się z punktem synchronicznej inspekcji.async-status-obietnicy załatwia sprawę. Jest asynchroniczny, ale nie
then
oczekuje na rozwiązanie obietnicy.źródło
Nie, brak interfejsu API do synchronizacji, ale oto moja wersja async
promiseState
(z pomocą @Matthijs):źródło
Promise.race([ Promise.resolve(p).then(() => "fulfilled", () => "rejected"), Promise.resolve().then(() => "pending") ]);
Chociaż wydaje mi się to bezpieczniejsze:const t = {}; return Promise.race([p,t]).then(v => v === t ? "pending" : "fulfilled", () => "rejected")
i pozwala uniknąć tworzenia dodatkowych obietnic, które są utrzymywane, dopóki oryginalne p jest w toku.Możesz zrobić wyścig z Promise.resolve
To nie jest synchroniczne, ale dzieje się teraz
Mały skrypt do testowania i zrozumienia ich znaczenia asynchronicznie
wyniki z opóźnieniem (0) (skomentuj czas opóźnienia)
i wyniki tego testu z firefoxem (chrome zachowaj kolejność)
promiseState make .race i. then: Level 2
źródło
'a value that p should not return'
użyj SymbolSymbol
byłaby unikalną wartością, dlatego nigdy nie musiałbyś zgadywać, której „wartość [...] p nie powinna zwracać”. Jednak równie dobrze działałoby odniesienie do określonego obiektu.Możesz użyć (brzydkiego) hacka w Node.js, dopóki nie zostanie zaoferowana metoda natywna:
źródło
Promise.prototype.isPending = function(){ return util.inspect(this).indexOf("<pending>")>-1; }
process.binding('util').getPromiseDetails
Promise.resolve('<pending>')
.w węźle, powiedzmy nieudokumentowane wewnętrzne
process.binding('util').getPromiseDetails(promise)
źródło
Zaktualizowano: 2019
Bluebird.js oferuje to: http://bluebirdjs.com/docs/api/isfulfilled.html
Jeśli wolisz stworzyć własne opakowanie, oto fajny blog o tym.
Ponieważ JavaScript jest jednowątkowy, trudno jest znaleźć wystarczająco powszechny przypadek użycia, aby uzasadnić umieszczenie go w specyfikacji. Najlepszym miejscem, aby dowiedzieć się, czy obietnica zostanie rozwiązana, jest .then (). Testowanie, czy obietnica jest wypełniona, stworzyłoby pętlę odpytywania, która najprawdopodobniej jest w złym kierunku.
async / await to fajna konstrukcja, jeśli chcesz synchronicznie rozumować kod asynchroniczny.
Innym przydatnym wywołaniem jest Promise.all ()
Kiedy po raz pierwszy sięgnąłem po tę odpowiedź, to jest przypadek użycia, którego szukałem.
źródło
W ten sposób możesz zawrzeć swoje obietnice
źródło
.then
zawsze wykonuje asynchronicznie OP, który chce sprawdzić obietnicę w tej samej turze , nie uzyska tutaj poprawnego wyniku. Uwaga OP zapytał konkretnie o inspekcję synchroniczną i wspomniał, że wie już o inspekcji asynchronicznej.To rzeczywiście dość denerwujące, że brakuje tej podstawowej funkcji. Jeśli używasz node.js, to znam dwa obejścia, żadne z nich nie są zbyt ładne. Oba poniższe fragmenty implementują ten sam interfejs API:
Wydaje się, że nie ma sposobu na rozróżnienie dwóch ostatnich stanów obietnicy za pomocą którejkolwiek ze sztuczek.
1. Użyj interfejsu API do debugowania V8
To ta sama sztuczka, której
util.inspect
używa.2. Synchronicznie uruchom mikrozadania
Pozwala to uniknąć debugowania API, ale ma przerażającą semantykę, powodując
process.nextTick
synchroniczne uruchamianie wszystkich oczekujących mikrozadań i wywołań zwrotnych. Ma to również efekt uboczny polegający na zapobieganiu wywoływaniu błędu „nieobsłużonego odrzucenia obietnicy” dla sprawdzonej obietnicy.źródło
process._tickCallback
(lub nawet zwykły% RunMicrotick) - losowo zepsuje rzeczy w kodzie. Desperacko próbowałem go uruchomić (głównie dla fałszywych timerów w funkcjach asynchronicznych) i nigdy nie był wystarczająco stabilny od strony węzła. Zrezygnowałem z pracy nad tym. Interfejs API lustrzanego debugowania V8 jest tutaj całkowicie odpowiedni.DeprecationWarning: DebugContext has been deprecated and will be removed in a future version.
:( Wygląda na to, że V8 go usunęłoprocess.binding('util').getPromiseDetails( promise )
zwraca w[ 0, ]
przypadku oczekujących,[ 1, value ]
wypełnionych i[ 2, value ]
odrzuconych.Uwaga: ta metoda wykorzystuje nieudokumentowane elementy wewnętrzne Node.js i może zostać zmieniona bez ostrzeżenia.
W Node możesz synchronicznie określić stan obietnicy za pomocą
process.binding('util').getPromiseDetails(/* promise */);
.To zwróci:
[0, ]
w toku,[1, /* value */]
za spełnione lub[2, /* value */]
za odrzucone.Pakowanie tego w funkcję pomocniczą:
źródło
jest
(co jest jedynym miejscem, w którym się nim interesuję). Funkcja istnieje, ale zawsze wydaje się powracaćundefined
. Jak dowiedzieć się, co się stało?mocha
; nigdy tego nie próbowałemjest
. Może zacznij nowe pytanie, łącząc się tutaj i dołącz swoją wersję Node.js, a takżejest
wersję?Promise
którego używałem tylko do testowania rzeczy, które powinny się dziać wPromise
toku, ale doszedłem do wniosku, że dopóki to, co napisałem, działa, nie ma potrzeby tego testować oprócz tego, co na tym polega.co możesz zrobić, to użyć zmiennej do przechowywania stanu, ręcznie ustawić stan na tę zmienną i sprawdzić tę zmienną.
oczywiście oznacza to, że musisz mieć dostęp do oryginalnego kodu promesy. Jeśli tego nie zrobisz, możesz:
Moje rozwiązanie to bardziej kodowanie, ale myślę, że prawdopodobnie nie musiałbyś tego robić dla każdej obietnicy, której używasz.
źródło
Począwszy od wersji 8 Node.js, możesz teraz używać pakietu Wise-Inspection do synchronicznego sprawdzania natywnych obietnic (bez niebezpiecznych hacków).
źródło
Możesz dodać metodę do Promise.prototype. To wygląda tak:
Edytowano: pierwsze rozwiązanie nie działa poprawnie, podobnie jak większość odpowiedzi tutaj. Zwraca wartość „pending” do momentu wywołania funkcji asynchronicznej „.then”, co nie następuje natychmiast. (To samo dotyczy rozwiązań wykorzystujących Promise.race). Moje drugie rozwiązanie rozwiązuje ten problem.
Możesz go użyć na dowolnej obietnicy. Na przykład:
Drugie (i poprawne) rozwiązanie:
I użyj go:
Uwaga : w tym rozwiązaniu nie musisz używać operatora „new”.
źródło
Oto bardziej dopracowana wersja QueryablePromise es6, umożliwiająca łączenie i przechwytywanie po pierwszym rozwiązaniu oraz natychmiastowe rozstrzygnięcie lub odrzucenie, aby interfejs API był zgodny z natywną obietnicą.
źródło
await
użycie do odpowiedzi @ jib , z idiomatycznym prototypowaniem.zwróć uwagę, że ta funkcja asynchroniczna jest wykonywana „prawie” natychmiast, jak funkcja zsynchronizowana (a właściwie prawdopodobnie natychmiast).
źródło
2019:
Najprostszym sposobem na zrobienie tego, jak wiem, jest
thenable
super cienkie opakowanie wokół obietnicy lub dowolna praca asynchroniczna.źródło
Możesz utworzyć własną podklasę, powiedzmy
QueryablePromise
, dziedzicząc zPromise
klasy dostępnej natywnie , której instancje miałybystatus
dostępną właściwość, której można użyć do synchronicznego sprawdzania stanu obiektów obietnicy . Implementacja nim można zobaczyć poniżej lub skierować to do lepszego wyjaśnienia.źródło
fetch
, zwróci rodzimą obietnicę. Jak twoja klasa pomogłaby w tym?const queryableFetch = new QueryablePromise((resolve, reject) => {fetch(/.../).then((data) => resolve(data)) })
? A może jest z tym jakiś problem? : /, err => reject(err)
jako drugi argumentthen
nie będzie poprawnie propagował błędów (między powodami jest uważany za anty-wzorzec konstruktora obietnicy ). Nie jest to jednak naprawdę synchroniczne (np. Nie wykryje już rozwiązanej obietnicy), ale może być przydatne w przypadkach, gdy nie kontrolujesz dzwoniącego, a odpowiedź jest potrzebna natychmiast.Istnieje inny elegancki i hacky sposób sprawdzenia, czy obietnica nadal oczekuje, po prostu konwertując cały obiekt na łańcuch i sprawdzając go za pomocą inspekcji w następujący sposób:
util.inspect(myPromise).includes("pending")
.Testowane na Node.js 8,9,10,11,12,13
Oto pełny przykład
Wynik:
źródło
Jeśli używasz eksperymentalnego ES7, możesz użyć asynchronicznego, aby łatwo zawrzeć obietnicę, której chcesz słuchać.
źródło
Napisałem mały pakiet npm, promise-value, który zawiera opakowanie obietnicy z
resolved
flagą:https://www.npmjs.com/package/promise-value
Daje również synchroniczny dostęp do wartości obietnicy (lub błędu). Nie zmienia to samego obiektu Promise, podążając za wzorcem zawijania zamiast rozszerzania.
źródło
To jest starsze pytanie, ale próbowałem zrobić coś podobnego. Muszę podtrzymać pracę n pracowników. Są zorganizowane w obietnicę. Muszę zeskanować i sprawdzić, czy zostały rozwiązane, odrzucone lub nadal oczekują. Jeśli problem zostanie rozwiązany, potrzebuję wartości, a jeśli zostanie odrzucona, zrób coś, aby rozwiązać problem lub oczekuję. Jeśli zostanie rozwiązany lub odrzucony, muszę rozpocząć kolejne zadanie, aby kontynuować. Nie mogę wymyślić sposobu, aby to zrobić z Promise.all lub Promise.race, ponieważ nadal pracuję z obietnicami w tablicy i nie mogę znaleźć sposobu, aby je usunąć. Więc tworzę pracownika, który załatwia sprawę
Potrzebuję funkcji generatora obietnic, która zwraca obietnicę, która w razie potrzeby rozpatruje lub odrzuca. Jest wywoływana przez funkcję, która tworzy ramy, aby wiedzieć, co robi obietnica.
W poniższym kodzie generator po prostu zwraca obietnicę na podstawie setTimeout.
Tutaj jest
doWork zwraca obiekt zawierający przyrzeczenie i jego stan oraz zwróconą wartość.
Poniższy kod uruchamia pętlę, która testuje stan i tworzy nowe procesy robocze, aby zachować 3 uruchomione procesy robocze.
Przetestowano w node.js.
Przy okazji, nie w tej odpowiedzi tak bardzo, ale w innych na podobne tematy NIENAWIDZĘ, gdy ktoś mówi „nie rozumiesz” lub „tak to nie działa”. Generalnie zakładam, że pytający wie, czego chce. Sugerowanie lepszego sposobu jest świetne. Cierpliwe wyjaśnienie, jak działają obietnice, również byłoby dobre.
źródło
Okazało się, że to rozwiązanie jest proste i pozwala mi nadal korzystać z natywnych obietnic, ale dodać przydatne kontrole synchroniczne. Nie musiałem też ściągać całej biblioteki obietnic.
OSTROŻNIE: Działa to tylko wtedy, gdy w bieżącym wątku wykonawczym występuje przerwa, aby umożliwić wykonanie obietnic PRZED sprawdzeniem konstrukcji synchronicznych. To sprawia, że ma to bardziej ograniczoną użyteczność, niż początkowo sądziłem - nadal jest przydatna w moim przypadku użycia (dzięki Benjaminowi Gruenbaumowi za wskazanie tego)
Z https://ourcodeworld.com/articles/read/317/how-to-check-if-a-javascript-promise-has-been-fulfilled-rejected-or-resolved, który oparł swoją odpowiedź na Czy istnieje sposób na powiedzieć, czy obietnica ES6 została spełniona / odrzucona / rozwiązana?
źródło
MakeQueryablePromise(Promise.resolve(3)).isResolved
jest fałszywa, ale obietnica jest całkiem oczywista. Nie wspominając o tym, że w odpowiedzi niepoprawnie użyto również terminów „rozwiązany” i „spełniony”. Aby to zrobić, wystarczy, że.then
sam dodasz program obsługi - co całkowicie mija się z punktem synchronicznej inspekcji.let wrappedPromise = MakeQueryablePromise(Promise.resolve(3)); setTimeout(function() {console.log(wrappedPromise.isFulfilled())}, 1);
Co tak długo, jak to robisz, działa dobrze. Ale musisz zrozumieć ten fakt, aby było to przydatne. Zaktualizuję opis z tym zastrzeżeniem. Zgadzam się też, że nazewnictwo funkcji mogłoby być lepsze / bardziej idiomatyczne.then
oryginalną obietnicę i osiągnąć to samo, ponieważ i tak jest asynchroniczna. Jest na to sposóbprocess.binding('util').getPromiseDetails
, który wydaje się działać, ale korzysta z prywatnego interfejsu API