Mam szereg obietnic, które realizuję Promise.all(arrayOfPromises);
Kontynuuję, aby kontynuować łańcuch obietnic. Wygląda mniej więcej tak
existingPromiseChain = existingPromiseChain.then(function() {
var arrayOfPromises = state.routes.map(function(route){
return route.handler.promiseHandler();
});
return Promise.all(arrayOfPromises)
});
existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
// do stuff with my array of resolved promises, eventually ending with a res.send();
});
Chcę dodać instrukcję catch, aby obsłużyć indywidualną obietnicę na wypadek błędu, ale gdy spróbuję, Promise.all
zwraca pierwszy znaleziony błąd (ignoruje resztę), a następnie nie mogę uzyskać danych z pozostałych obietnic w tablica (to nie błąd).
Próbowałem zrobić coś takiego ...
existingPromiseChain = existingPromiseChain.then(function() {
var arrayOfPromises = state.routes.map(function(route){
return route.handler.promiseHandler()
.then(function(data) {
return data;
})
.catch(function(err) {
return err
});
});
return Promise.all(arrayOfPromises)
});
existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {
// do stuff with my array of resolved promises, eventually ending with a res.send();
});
Ale to nie rozwiązuje problemu.
Dzięki!
-
Edytować:
Poniższe odpowiedzi były całkowicie prawdziwe, kod łamał się z innych powodów. Jeśli ktoś jest zainteresowany, oto rozwiązanie, w którym znalazłem ...
Łańcuch Node Express Server
serverSidePromiseChain
.then(function(AppRouter) {
var arrayOfPromises = state.routes.map(function(route) {
return route.async();
});
Promise.all(arrayOfPromises)
.catch(function(err) {
// log that I have an error, return the entire array;
console.log('A promise failed to resolve', err);
return arrayOfPromises;
})
.then(function(arrayOfPromises) {
// full array of resolved promises;
})
};
Wywołanie API (wywołanie route.async)
return async()
.then(function(result) {
// dispatch a success
return result;
})
.catch(function(err) {
// dispatch a failure and throw error
throw err;
});
Uruchamianie systemu .catch
za Promise.all
zanim .then
Wydaje się, że służył łapania błędów od pierwotnych obietnic, ale potem wraca całą tablicę do następnego.then
Dzięki!
.then(function(data) { return data; })
można całkowicie pominąćthen
lubcatch
handlerach i jest w nim błąd. Nawiasem mówiąc, czy ten węzeł?Odpowiedzi:
Promise.all
jest wszystkim albo niczym. Rozpatruje się, gdy wszystkie obietnice w tablicy zostaną rozpatrzone lub odrzuć, gdy tylko jedna z nich odrzuci. Innymi słowy, albo rozwiązuje z tablicą wszystkich rozwiązanych wartości, albo odrzuca z pojedynczym błędem.Niektóre biblioteki mają coś zwanego
Promise.when
, co, jak rozumiem, zamiast tego czekałoby, aż wszystkie obietnice w tablicy zostaną rozwiązane lub odrzucone, ale nie znam tego i nie ma go w ES6.Twój kod
Zgadzam się z innymi tutaj, że Twoja poprawka powinna działać. Powinno to zostać rozwiązane za pomocą tablicy, która może zawierać mieszankę udanych wartości i obiektów błędów. Rzadko zdarza się przekazywać obiekty błędów na ścieżce sukcesu, ale zakładając, że kod ich oczekuje, nie widzę z tym problemu.
Jedynym powodem, dla którego mogę wymyślić, dlaczego „nie można rozwiązać”, jest to, że nie działa kod, którego nam nie pokazujesz, a powodem, dla którego nie widzisz żadnego komunikatu o błędzie, jest to, że ten łańcuch obietnic nie jest zakończony końcową catch (o ile i tak nam pokazujesz).
Pozwoliłem sobie na uwzględnienie „istniejącego łańcucha” z twojego przykładu i zakończenie łańcucha z haczykiem. To może nie być odpowiednie dla ciebie, ale dla osób czytających to ważne jest, aby zawsze zwracać lub kończyć łańcuchy, lub potencjalne błędy, nawet błędy w kodowaniu, zostaną ukryte (co, jak podejrzewam, miało miejsce tutaj):
źródło
Promise.allSettled()
z przyzwoitym wsparciem. Zobacz referencje .Promise.all
nie powiedzie się, gdy pierwszy wątek zawiedzie Ale niestety wszystkie pozostałe wątki nadal działają, dopóki się nie zakończą. Nic nie jest anulowane, a nawet gorzej: Nie ma możliwości anulowania wątkuPromise
. Zatem cokolwiek robią (i manipulują) wątki, kontynuują, zmieniają stany i zmienne, używają procesora, ale na koniec nie zwracają wyniku. Musisz być tego świadomy, aby nie wywoływać chaosu, np. Podczas powtarzania / ponawiania połączenia.NOWA ODPOWIEDŹ
PRZYSZŁA obietnica API
źródło
e
nie musi to byćError
. Może to być ciąg znaków, na przykład, jeśli ktoś go zwróciPromise.reject('Service not available')
..then()
i.catch()
.Promise.resolve()
przekazałby wartość pierwszemu, podczas gdyPromise.reject()
przekazałby ją drugiemu. Można owinąć je w obiekcie npp.then(v => ({success: true, value: v})).catch(e => ({success: false, error: e}))
.Aby kontynuować
Promise.all
pętlę (nawet gdy Obietnica odrzuca), napisałem funkcję narzędziową, która jest wywoływanaexecuteAllPromises
. Ta funkcja narzędzia zwraca obiekt za pomocąresults
ierrors
.Chodzi o to, że wszystkie obietnice, które przekażesz,
executeAllPromises
zostaną opakowane w nową obietnicę, która zawsze będzie rozpatrywana. Nowa obietnica jest rozpatrywana za pomocą tablicy z 2 punktami. Pierwsze miejsce zawiera wartość rozstrzygającą (jeśli istnieje), a drugie miejsce utrzymuje błąd (jeśli opakowana obietnica odrzuca).W ostatnim kroku
executeAllPromises
kumuluje wszystkie wartości zapakowanych obietnic i zwraca ostateczny obiekt z tablicą dlaresults
i tablicą dlaerrors
.Oto kod:
źródło
ES2020 wprowadza nową metodę typu Promise:
Promise.allSettled()
Promise.allSettled daje sygnał, gdy wszystkie obietnice wejściowe zostaną rozliczone, co oznacza, że są one spełnione lub odrzucone. Jest to przydatne w przypadkach, gdy nie zależy ci na stanie obietnicy, chcesz tylko wiedzieć, kiedy praca jest wykonywana, niezależnie od tego, czy się powiedzie.
Przeczytaj więcej w poście na blogu v8 https://v8.dev/features/promise-combinators
źródło
Jak powiedział @jib,
Możesz jednak kontrolować niektóre obietnice, które „mogą” zawieść i chcielibyśmy kontynuować
.then
.Na przykład.
źródło
jeśli skorzystasz z biblioteki q https://github.com/kriskowal/q , ma ona metodę q.allSettled (), która może rozwiązać ten problem, możesz obsłużyć każdą obietnicę w zależności od jej stanu albo pełna, albo odrzucona,
źródło
q
), bardziej przydatne byłoby podanie przykładu użycia związanego z pytaniem. W obecnej formie odpowiedź nie wyjaśnia, w jaki sposób ta biblioteka może pomóc w rozwiązaniu problemu.Korzystanie z Async oczekuje -
tutaj jedna funkcja asynchroniczna func1 zwraca wartość rozwiązaną, a func2 zgłasza błąd i zwraca wartość null w tej sytuacji, możemy sobie z tym poradzić tak, jak chcemy i odpowiednio zwrócić.
Dane wyjściowe to - ['func1', null]
źródło
Dla osób używających ES8, które się tutaj natkną, możesz wykonać następujące czynności, używając funkcji asynchronicznych :
źródło
Możemy obsłużyć odrzucenie na poziomie indywidualnych obietnic, więc gdy otrzymamy wyniki w naszej tablicy wyników, indeks tablicy, który został odrzucony, będzie
undefined
. Możemy poradzić sobie z tą sytuacją w razie potrzeby i wykorzystać pozostałe wyniki.Tutaj odrzuciłem pierwszą obietnicę, więc jest ona niezdefiniowana, ale możemy wykorzystać wynik drugiej obietnicy, która ma indeks 1.
źródło
Czy rozważałeś
Promise.prototype.finally()
?Wygląda na to, że został zaprojektowany tak, aby robić dokładnie to, co chcesz - wykonać funkcję, gdy wszystkie obietnice zostaną rozliczone (rozwiązane / odrzucone), niezależnie od niektórych obietnic odrzuconych.
Z dokumentacji MDN :
Ta
finally()
metoda może być przydatna, jeśli chcesz wykonać przetwarzanie lub czyszczenie po rozliczeniu obietnicy, niezależnie od jej wyniku.finally()
Metoda jest bardzo podobna do wywoływania.then(onFinally, onFinally)
jednak istnieje kilka różnic:Podczas tworzenia funkcji wbudowanej można ją przekazać raz, zamiast zmuszać ją do dwukrotnego zadeklarowania lub utworzenia dla niej zmiennej.
Ostatecznie wywołanie zwrotne nie otrzyma żadnego argumentu, ponieważ nie ma wiarygodnych sposobów ustalenia, czy obietnica została spełniona, czy odrzucona. Ten przypadek użycia jest właśnie wtedy, gdy nie obchodzi Cię powód odrzucenia lub wartość spełnienia, a więc nie musisz go podawać.
W przeciwieństwie do
Promise.resolve(2).then(() => {}, () => {})
(który zostanie rozwiązany z niezdefiniowanym),Promise.resolve(2).finally(() => {})
zostanie rozwiązany z 2. Podobnie, w przeciwieństwie doPromise.reject(3).then(() => {}, () => {})
(który zostanie spełniony z niezdefiniowanym),Promise.reject(3).finally(() => {})
zostanie odrzucony z 3.== Awaria ==
Jeśli Twoja wersja JavaScript nie obsługuje
Promise.prototype.finally()
, możesz skorzystać z tego obejścia od Jake'a Archibalda :Promise.all(promises.map(p => p.catch(() => undefined)));
źródło
Promises.allSettled()
zostanie faktycznie zaimplementowany (jest to udokumentowane tutaj przez MDN ), wtedyPromises.all.finally()
wydaje się, że osiągnie to samo. Zaraz spróbuję ...allSettled()
.allSettled()
nie jest nigdzie (jeszcze) zaimplementowany, więc nie chcę wyprzedzać rzeczywistości. Miałem sukcesPromises.all(myPromiseArray).finally()
i to pasuje do tej odpowiedzi. Gdy jużallSettled()
istnieje, mogę go przetestować i dowiedzieć się, jak to działa. Do tego czasu, kto wie, co faktycznie zaimplementują przeglądarki? Chyba że masz najnowsze informacje, które wręcz przeciwnie ...Promise.allSettled
nie jest zaimplementowany w Firefox, ale wydaje się, że istnieje w Chrome. To, że doktorzy mówią, że jest zaimplementowane, nie oznacza, że tak naprawdę jest zaimplementowane. Nie zamierzam go używać w najbliższym czasie.Alternatywnie, jeśli masz przypadek, w którym nie zależy ci szczególnie na wartościach rozwiązanych obietnic, gdy występuje jedna awaria, ale nadal chcesz, aby się spełniły, możesz zrobić coś takiego, co rozwiązuje się z obietnicami normalnie, gdy wszyscy odnoszą sukces i odrzucają obietnice, których nie dotrzymują:
źródło
Zawsze możesz zawinąć funkcje zwracające obietnicę w taki sposób, że wychwytują awarię i zwracają zamiast tego uzgodnioną wartość (np. Error.message), więc wyjątek nie zwinie się aż do funkcji Promise.all i ją wyłączy.
źródło
Znalazłem sposób (obejście), aby to zrobić bez synchronizacji.
Jak już wspomniano wcześniej, nie
Promise.all
ma żadnego.więc ... Użyj załączonej obietnicy, aby złapać i zmusić rozwiązanie.
źródło
Musisz wiedzieć, jak rozpoznać błąd w wynikach. Jeśli nie masz standardowego oczekiwanego błędu, sugeruję przeprowadzenie transformacji dla każdego błędu w bloku catch, który umożliwia jego identyfikację w wynikach.
źródło
Nie jest to najlepszy sposób na zapisywanie błędów, ale zawsze możesz ustawić wszystko na tablicę dla promiseAll i zapisać uzyskane wyniki w nowych zmiennych.
Jeśli używasz GraphQL, musisz przetworzyć odpowiedź niezależnie od tego, a jeśli nie znajdzie poprawnego odwołania, spowoduje to awarię aplikacji, zawężając zakres problemu
źródło
Tak
Promise.all
jest zaprojektowany do pracy. Jeśli jest jedna obietnicareject()
, cała metoda natychmiast zawodzi.Są przypadki użycia, w których można chcieć, aby
Promise.all
obietnice dopuszczające się nie spełniły. Aby tak się stało, po prostu nie używaj żadnychreject()
oświadczeń w obietnicy. Jednak, aby upewnić się, że twoja aplikacja / skrypt nie zawiesza się w przypadku, gdy żadna bazowa obietnica nigdy nie otrzyma odpowiedzi, musisz poświęcić jej czas.źródło
reject()
w obietnicy jest w porządku, ale co zrobić, jeśli trzeba skorzystać z obietnic innej biblioteki?Napisałem bibliotekę npm, aby uporać się z tym problemem piękniej. https://github.com/wenshin/promiseallend
zainstalować
2017-02-25 nowy API, to nie jest złamanie obietnicy zasad
———————————————————————————————
Stare złe API, nie używaj go!
źródło
Promise.all
. Ale zbierze wszystkie dane i błędy każdej obietnicy. obsługuje także wprowadzanie obiektów, to nie jest punkt. po zebraniu wszystkich danych i błędów zastępujępromise.then
metodę postępowania z zarejestrowanymi wywołaniami zwrotnymi, które obejmują odrzucenie i spełnienie. Szczegółowe informacje można znaleźć w kodzieonFulfilled
ionRejected
programy obsługi, które są przekazywanethen
?fulfilled
irejected
. Ale tak naprawdę powoduje, że trudny problem jest zgodny ze wszystkimi obietnicami użycia normalnie, jakonFulfilled
ionRejected
wszystkie zwracająPromise.reject()
lubPromise.resolve()
. Jak dotąd nie jestem pewien, jak to rozwiązać, czy ktoś ma lepszy pomysł? Najlepszą odpowiedzią na ten problem jest to, że nie może on filtrować danych i błędów w środowisku przeglądarki.