Powiedzmy, że mam funkcję uwierzytelnienia, która zwraca obietnicę. Obietnica rozwiązuje się z wynikiem. Fałsz i prawda są oczekiwanymi rezultatami, tak jak ja to widzę, a odrzucenia powinny wystąpić tylko w przypadku błędu. A może niepowodzenie w uwierzytelnianiu to coś, za co odrzucisz obietnicę?
javascript
Mathieu Bertin
źródło
źródło
reject
i nie zwróci false, ale jeśli spodziewasz wartość byćBool
, to były udane i należy rozwiązać z Bool niezależnie od wartości. Obietnice są swego rodzaju proxy dla wartości - przechowują zwróconą wartość, więc tylko wtedy, gdy nie można jej uzyskaćreject
. W przeciwnym razie powinieneśresolve
.false
lub zgłoszenie wyjątku?then
gdy serwer odpowiada - nawet jeśli zostanie zwrócony kod błędu - i musisz to sprawdzićresponse.ok
. Programcatch
obsługi jest uruchamiany tylko w przypadku nieoczekiwanych błędów.Odpowiedzi:
Dobre pytanie! Nie ma trudnej odpowiedzi. To zależy od tego, co uważasz za wyjątkowe w tym konkretnym punkcie przepływu .
Odrzucenie a
Promise
jest tym samym, co zgłoszenie wyjątku. Nie wszystkie niepożądane wyniki są wyjątkowe , są wynikiem błędów . Możesz argumentować swoją sprawę na dwa sposoby:Uwierzytelniania nie powinien , ponieważ rozmówca spodziewa się obiektu w zamian, a wszystko inne jest wyjątek od tego przepływu.
reject
Promise
User
Uwierzytelniania nie powinien , aczkolwiek , ponieważ dostarczanie niewłaściwych referencji nie jest naprawdę wyjątkowy przypadek, a dzwoniący nie należy oczekiwać, że przepływ zawsze skutkować .
resolve
Promise
null
User
Pamiętaj, że patrzę na problem od strony dzwoniącego . Czy w przepływie informacji osoba dzwoniąca oczekuje, że jego działania spowodują błąd
User
(a cokolwiek innego jest błędem), czy może ma sens, aby ten konkretny rozmówca obsługiwał inne wyniki?W systemie wielowarstwowym odpowiedź może się zmieniać w miarę przepływu danych przez warstwy. Na przykład:
null
użytkownika.Ten 4-punktowy przykład jest oczywiście skomplikowany, ale ilustruje 2 punkty:
Więc znowu, nie ma twardej odpowiedzi. Czas pomyśleć i zaprojektować!
źródło
Więc obietnice mają fajną właściwość, że przynoszą JS z języków funkcjonalnych, to znaczy, że faktycznie implementują ten
Either
konstruktor typów, który skleja dwa inne typy,Left
typ iRight
typ, zmuszając logikę do przyjęcia jednej gałęzi lub drugiej Oddział.Teraz rzeczywiście zauważasz, że typ po lewej stronie jest niejednoznaczny w odniesieniu do obietnic; możesz odrzucić za pomocą wszystkiego. To prawda, ponieważ JS jest słabo wpisany, ale chcesz zachować ostrożność, jeśli programujesz w defensywie.
Powodem jest to, że JS weźmie
throw
wyciągi z kodu obsługującego obietnice i umieści go również poLeft
stronie tego. Technicznie w JS możeszthrow
wszystko, w tym prawda / fałsz, ciąg znaków lub liczbę: ale kod JavaScript wyrzuca rzeczy bezthrow
(gdy robisz takie rzeczy, jak próba uzyskania dostępu do właściwości na wartości null) i istnieje ustalone API dla tego (Error
obiektu) . Więc kiedy zaczynasz łapać, zazwyczaj dobrze jest założyć, że te błędy sąError
obiektami. A ponieważreject
obietnica for będzie gromadzić się w dowolnych błędach któregokolwiek z powyższych błędów, generalnie chcesz tylkothrow
inne błędy, aby twojecatch
oświadczenie miało prostą, spójną logikę.Dlatego chociaż można umieścić if-warunkowy w swoim
catch
i szukać fałszywych błędów, w tym przypadku sprawa jest banalna prawda,prawdopodobnie wolisz strukturę logiczną, przynajmniej dla tego, co pochodzi bezpośrednio z uwierzytelniacza, prostszej wartości logicznej:
W rzeczywistości kolejnym poziomem logiki uwierzytelnienia jest prawdopodobnie zwrócenie jakiegoś
User
obiektu zawierającego uwierzytelnionego użytkownika, co powoduje , że staje się:i mniej więcej tego się spodziewałbym: powróć
null
w przypadku, gdy użytkownik nie jest zdefiniowany, w przeciwnym razie powróć{user_id: <number>, permission_to_launch_missiles: <boolean>}
. Spodziewałbym się, że ogólny przypadek braku zalogowania jest możliwy do odzyskania, na przykład, jeśli jesteśmy w trybie demonstracyjnym dla nowych klientów i nie powinniśmy mieszać się z błędami, do których przypadkowo zadzwoniłem,object.doStuff()
kiedyobject.doStuff
byłemundefined
.Teraz powiedział, że to, co możesz zrobić, to określić
NotLoggedIn
czyPermissionError
wyjątek, który wywodziError
. Następnie w rzeczach, które naprawdę tego potrzebują, chcesz napisać:źródło
Błędy
Porozmawiajmy o błędach.
Istnieją dwa rodzaje błędów:
Oczekiwane błędy
Oczekiwane błędy to stany, w których dzieje się coś złego, ale wiesz, że tak, więc sobie z tym poradzisz.
Są to rzeczy takie jak dane wejściowe użytkownika lub żądania serwera. Wiesz, że użytkownik może popełnić błąd lub serwer może nie działać, więc napisz kod sprawdzający, aby upewnić się, że program ponownie poprosi o wprowadzenie danych, wyświetli komunikat lub cokolwiek innego, co jest odpowiednie.
Można je odzyskać, gdy są obsługiwane. Pozostawione bez obsługi stają się nieoczekiwanymi błędami.
Nieoczekiwane błędy
Nieoczekiwane błędy (błędy) to stany, w których dzieje się coś złego, ponieważ kod jest nieprawidłowy. Wiesz, że w końcu się zdarzą, ale nie ma sposobu, aby wiedzieć, gdzie i jak sobie z nimi poradzić, ponieważ z definicji są nieoczekiwane.
Są to między innymi błędy składniowe i logiczne. Być może masz literówkę w kodzie, mogłeś wywołać funkcję z niewłaściwymi parametrami. Zazwyczaj nie można ich odzyskać.
try..catch
Porozmawiajmy o tym
try..catch
.W JavaScript
throw
nie jest powszechnie używany. Jeśli rozejrzysz się za przykładami w kodzie, to będzie ich niewiele i zwykle są zbudowane według liniiZ tego powodu
try..catch
bloki nie są tak często spotykane w przepływie sterowania. Zazwyczaj dość łatwo jest dodać kilka sprawdzeń przed wywołaniem metod, aby uniknąć oczekiwanych błędów.Środowiska JavaScript są również dość wybaczające, więc nieoczekiwane błędy również często pozostają niezauważone.
C # :try..catch
nie musi być rzadkie. Istnieje kilka fajnych przypadków użycia, które są bardziej powszechne w językach takich jak Java i C #. Java i C # mają tę zaletęcatch
, że można je rozróżnić między oczekiwanymi i nieoczekiwanymi błędami:Ten przykład pozwala przepłynąć innym nieoczekiwanym wyjątkom i zająć się nimi gdzie indziej (na przykład poprzez zalogowanie i zamknięcie programu).
W JavaScript ta konstrukcja może być replikowana poprzez:
Nie tak elegancki, co jest jednym z powodów, dla których jest to rzadkie.
Funkcje
Porozmawiajmy o funkcjach.
Jeśli zastosujesz zasadę pojedynczej odpowiedzialności , każda klasa i funkcja powinna służyć jednemu celowi.
Na przykład
authenticate()
może uwierzytelnić użytkownika.Może to być zapisane jako:
Alternatywnie można go zapisać jako:
Oba są dopuszczalne.
Obietnice
Porozmawiajmy o obietnicach.
Obietnice są formą asynchroniczną
try..catch
. Dzwonięnew Promise
lubPromise.resolve
uruchamiatry
kod. Dzwonięthrow
lubPromise.reject
wysyła cię nacatch
kod.Jeśli masz funkcję asynchroniczną do uwierzytelnienia użytkownika, możesz zapisać go jako:
Alternatywnie można go zapisać jako:
Oba są dopuszczalne.
Zagnieżdżanie
Porozmawiajmy o zagnieżdżaniu.
try..catch
można zagnieżdżać. Twojaauthenticate()
metoda może miećtry..catch
blok wewnętrzny, taki jak:Podobnie obietnice mogą być zagnieżdżone. Twoja
authenticate()
metoda asynchroniczna może wewnętrznie wykorzystywać obietnice:Więc jaka jest odpowiedź?
Ok, myślę, że nadszedł czas, abym faktycznie odpowiedział na pytanie:
Najprostszą odpowiedzią, jaką mogę udzielić, jest to, że powinieneś odrzucić obietnicę w dowolnym miejscu, w którym inaczej byłby
throw
wyjątek, gdyby był to kod synchroniczny.Jeśli przepływ kontroli jest prostszy dzięki kilku
if
kontrolom wthen
wyciągach, nie musisz odrzucać obietnicy.Jeśli przepływ kontroli jest prostszy, odrzucając obietnicę, a następnie sprawdzając rodzaje błędów w kodzie obsługi błędów, zrób to zamiast tego.
źródło
Użyłem gałęzi „odrzucenia” obietnicy do reprezentowania akcji „anuluj” w oknach dialogowych interfejsu użytkownika jQuery. Wydawało się to bardziej naturalne niż używanie gałęzi „rozwiązuj”, zwłaszcza dlatego, że w oknie dialogowym często znajduje się wiele opcji „zamykania”.
źródło
Obsługa obietnicy jest mniej więcej taka, jak warunek „jeśli”. Od Ciebie zależy, czy chcesz „rozwiązać”, czy „odrzucić”, jeśli uwierzytelnienie się nie powiedzie.
źródło
try..catch
, nieif
.try...catch
i po prostu powiedzieć, że jeśli byłeś w stanie wypełnić i uzyskać wynik, powinieneś rozwiązać niezależnie od otrzymanej wartości, w przeciwnym razie powinieneś odrzucić?try { if (!doSomething()) throw whatever; doSomethingElse() } catch { ... }
jest całkowicie w porządku, ale konstrukcja, którąPromise
reprezentuje a, jesttry..catch
częścią, a nieif
częścią.doSomething()
zawiedzie, to rzuci, ale jeśli nie, może zawierać potrzebną wartość (twojeif
powyższe jest nieco mylące, ponieważ nie jest częścią twojego pomysłu tutaj :)). Powinieneś odrzucić tylko, jeśli istnieje powód do rzucenia (w analogii), więc jeśli test się nie powiódł. Jeśli test się powiedzie, zawsze powinieneś rozwiązać, niezależnie od tego, czy jego wartość jest dodatnia, prawda?