JavaScript rozwijam od kilku lat i wcale nie rozumiem zamieszania związanego z obietnicami.
Wygląda na to, że wszystko, co robię, to zmiana:
api(function(result){
api2(function(result2){
api3(function(result3){
// do work
});
});
});
I tak mógłbym użyć biblioteki takiej jak asynchroniczna , z czymś takim jak:
api().then(function(result){
api2().then(function(result2){
api3().then(function(result3){
// do work
});
});
});
Co jest bardziej kodem i mniej czytelnym. Nic tu nie zyskałem, nie jest też nagle magicznie „płaskie”. Nie wspominając już o konieczności przekształcania rzeczy w obietnice.
Więc o co tyle zamieszania w związku z obietnicami?
Odpowiedzi:
Obietnice nie są oddzwanianiem. Obietnica reprezentuje przyszły wynik operacji asynchronicznej . Oczywiście, pisząc je tak, jak robisz, nie zyskujesz zbyt wiele. Ale jeśli napiszesz je zgodnie z przeznaczeniem, możesz napisać kod asynchroniczny w sposób podobny do kodu synchronicznego i łatwiejszy do naśladowania:
Z pewnością nie mniej kodu, ale o wiele bardziej czytelny.
Ale to nie koniec. Odkryjmy prawdziwe korzyści: co zrobić, jeśli chcesz sprawdzić, czy w którymkolwiek z kroków nie ma błędu? Byłoby piekło robić to z oddzwanianiem, ale z obietnicami to bułka z masłem:
Prawie tak samo jak
try { ... } catch
blok.Nawet lepiej:
A nawet lepiej: Co jeśli te rozmowy do 3
api
,api2
,api3
może uruchomić jednocześnie (na przykład gdyby były rozmowy AJAX), ale trzeba było czekać na trzech? Bez obietnic powinieneś stworzyć jakiś licznik. Z obietnicami, używając notacji ES6, jest kolejna bułka z masłem:Mam nadzieję, że teraz widzisz obietnice w nowym świetle.
źródło
api2
i działają operacje asynchroniczneapi3
? czy ostatnia.then
zostanie wywołana dopiero po zakończeniu operacji asynchronicznych?Tak, obietnice są asynchronicznymi wywołaniami zwrotnymi. Nie mogą zrobić niczego, czego nie mogą zrobić wywołania zwrotne, a ty masz do czynienia z tymi samymi problemami z asynchronicznością, co z zwykłymi wywołaniami zwrotnymi.
Jednak obietnice są czymś więcej niż tylko wywołaniami zwrotnymi. Są bardzo potężną abstrakcją, pozwalają na czystszy i lepszy, funkcjonalny kod z mniej podatną na błędy płytą kotłową.
Obietnice są obiektami reprezentującymi wynik pojedynczego (asynchronicznego) obliczenia. Oni rozwiązać do tego wyniku tylko raz. Jest kilka rzeczy, co to oznacza:
Obietnice wdrażają wzorzec obserwatora:
return
stworzyć obiekt PromiseObietnice są łańcuchowe ( monadyczne , jeśli chcesz ):
.then()
metody. Wywołanie zwrotne zostanie wywołane z pierwszym wynikiem i zwróci obietnicę dotyczącą wyniku obietnicy, którą zwraca wywołanie zwrotne.Brzmi skomplikowanie? Czas na przykładowy kod.
Spłaszczanie nie przychodzi magicznie, ale możesz to łatwo zrobić. W przypadku mocno zagnieżdżonego przykładu (prawie) odpowiednikiem byłoby
Jeśli zapoznanie się z kodem tych metod pomaga zrozumieć, oto najbardziej podstawowa biblioteka obietnic w kilku wierszach .
Abstrakcja Promise umożliwia znacznie lepszą kompozycyjność funkcji. Na przykład, obok
then
łańcucha,all
funkcja tworzy obietnicę dla połączonego wyniku wielu obietnic oczekiwania równoległego.Wreszcie, obietnice pochodzą ze zintegrowaną obsługą błędów. Wynik obliczeń może być taki, że albo obietnica zostanie spełniona z wartością, albo zostanie odrzucona z uzasadnionego powodu. Wszystkie funkcje kompozycji obsługują to automatycznie i propagują błędy w łańcuchach obietnic, dzięki czemu nie musisz się tym wszystkim przejmować - w przeciwieństwie do implementacji zwykłego wywołania zwrotnego. Na koniec możesz dodać dedykowane wywołanie zwrotne błędu dla wszystkich występujących wyjątków.
To całkiem trywialne w przypadku dobrych bibliotek obietnic, zobacz Jak przekonwertować istniejące API zwrotne na obietnice?
źródło
.then(console.log)
, ponieważ console.log zależy od kontekstu konsoli. W ten sposób spowoduje to nielegalny błąd wywołania. Użyjconsole.log.bind(console)
lub,x => console.log(x)
aby powiązać kontekst.console
metody są już powiązane. I oczywiście powiedziałem tylko, że oba gniazda mają dokładnie takie samo zachowanie, nie że żadne z nich zadziała :-POprócz już ustalonych odpowiedzi, dzięki funkcjom strzałek ES6 Obietnice zmieniają się ze skromnie świecącego małego niebieskiego karła prosto w czerwonego olbrzyma. To ma zamiar zapaść się w supernową:
Jak zauważył oligofren , bez argumentów między wywołaniami API nie potrzebujesz w ogóle anonimowych funkcji otoki:
I wreszcie, jeśli chcesz osiągnąć supermasywny poziom czarnej dziury, możesz oczekiwać obietnic:
źródło
apiX
metodach, równie dobrze można pominąć funkcje strzałek w sumie:api().then(api2).then(api3).then(r3 => console.log(r3))
.Oprócz świetnych odpowiedzi powyżej można dodać 2 dodatkowe punkty:
1. Różnica semantyczna:
Obietnice mogą zostać rozwiązane już po stworzeniu. Oznacza to, że gwarantują warunki, a nie zdarzenia . Jeśli są już rozwiązane, przekazana do nich funkcja rozstrzygania jest nadal wywoływana.
I odwrotnie, wywołania zwrotne obsługują zdarzenia. Tak więc, jeśli zdarzenie, które Cię interesuje, miało miejsce przed zarejestrowaniem oddzwaniania, oddzwanianie nie jest wywoływane.
2. Odwrócenie kontroli
Oddzwanianie obejmuje odwrócenie kontroli. Po zarejestrowaniu funkcji wywołania zwrotnego w dowolnym interfejsie API środowisko wykonawcze JavaScript zapisuje funkcję wywołania zwrotnego i wywołuje ją z pętli zdarzeń, gdy jest gotowa do uruchomienia.
Patrz Pętla JavaScript zdarzeń o wyjaśnienia.
W przypadku obietnic kontrola znajduje się w programie wywołującym. Metodę .then () można wywołać w dowolnym momencie, jeśli przechowujemy obiekt promise.
źródło
Oprócz innych odpowiedzi, składnia ES2015 bezproblemowo łączy się z obietnicami, redukując jeszcze więcej kodu podstawowego:
źródło
Obietnice nie są wywołaniami zwrotnymi, oba są programistycznymi idiomami, które ułatwiają programowanie asynchroniczne. Użycie programowania w stylu async / Oczekiwanie przy użyciu coroutines lub generatorów, które zwracają obietnice, można uznać za trzeci taki idiom. Porównanie tych idiomów w różnych językach programowania (w tym Javascript) znajduje się tutaj: https://github.com/KjellSchubert/promise-future-task
źródło
Nie, wcale nie.
Wywołania zwrotne to po prostu funkcje w JavaScript, które należy wywoływać, a następnie wykonywać po zakończeniu wykonywania innej funkcji. Jak to się dzieje?
W rzeczywistości w JavaScript funkcje są uważane za obiekty, a zatem jak wszystkie inne obiekty, nawet funkcje mogą być wysyłane jako argumenty do innych funkcji . Najczęstszym i ogólnym przypadkiem użycia, o jakim można pomyśleć, jest funkcja setTimeout () w JavaScript.
Obietnice to nic więcej, ale znacznie bardziej improwizowane podejście do obsługi i strukturyzacji kodu asynchronicznego w porównaniu do robienia tego samego z wywołaniami zwrotnymi.
Obietnica odbiera dwa wywołania zwrotne w funkcji konstruktora: rozwiązywanie i odrzucanie. Te obietnice zwrotne w obietnicach zapewniają nam szczegółową kontrolę nad obsługą błędów i przypadkami powodzenia. Wywołanie zwrotne rozstrzygania jest używane, gdy wykonanie obietnicy zakończyło się powodzeniem, a wywołanie odrzucenia jest używane do obsługi przypadków błędów.
źródło
Żadne obietnice nie są tylko opakowaniem zwrotnym
przykład Możesz użyć rodzimych obietnic javascript z węzłem js
źródło
Obietnice JavaScript faktycznie używają funkcji zwrotnych, aby określić, co zrobić po rozwiązaniu lub odrzuceniu obietnicy, dlatego obie nie różnią się zasadniczo. Główną ideą obietnic jest przyjmowanie wywołań zwrotnych - zwłaszcza zagnieżdżonych wywołań zwrotnych, w których chcesz wykonać jakieś czynności, ale byłoby to bardziej czytelne.
źródło
Przegląd obietnic:
W JS możemy zawijać operacje asynchroniczne (np. Wywołania bazy danych, wywołania AJAX) w obietnice. Zwykle chcemy uruchomić dodatkową logikę na pobranych danych. Obietnice JS mają funkcje obsługi, które przetwarzają wynik operacji asynchronicznych. Funkcje modułu obsługi mogą zawierać nawet inne operacje asynchroniczne, które mogą polegać na wartości poprzednich operacji asynchronicznych.
Obietnica zawsze ma 3 następujące stany:
Oczekująca obietnica może zostać rozstrzygnięta / wypełniona lub odrzucona za pomocą wartości. Następnie wywoływane są następujące metody obsługi, które przyjmują wywołania zwrotne jako argumenty:
Promise.prototype.then()
: Po rozwiązaniu obietnicy zostanie wywołany argument wywołania zwrotnego tej funkcji.Promise.prototype.catch()
: Gdy obietnica zostanie odrzucona, zostanie wywołany argument wywołania zwrotnego tej funkcji.Mimo że powyższe metody zdobywają argumenty wywołania zwrotnego, są znacznie lepsze niż używanie tylko wywołań zwrotnych tutaj, jest to przykład, który wiele wyjaśni:
Przykład
then
wywoływana jest pierwsza metoda, a rozstrzygnięta wartość jest przekazywana jako argument wywołania zwrotnegocatch
wywoływana jest pierwsza metoda, a odrzucona wartość jest przekazywana jako argumentcatch
Ithen
metody powrotu obietnic, dlatego możemy je łańcuch. Zawijają wszystkie zwracane wartościPromise.resolve
i dowolne wartości wyrzucane (przy użyciuthrow
słowa kluczowego) wPromise.reject
. Tak więc każda zwracana wartość jest przekształcana w obietnicę i na tej obietnicy możemy ponownie wywołać funkcję modułu obsługi.catch
metoda obsługuje wszystkie błędy, które wystąpiły przedcatch
modułem obsługi.źródło