Będzie to pierwszy wpis z serii postów o asynchronicznym kodzie w języku JavaScript. Na początek obiekty typu Promise
,
czyli obietnice jakieś wartości.
Na początku kiedy została „odkryta” możliwość używania obiektów XMLHttpRequest
, do wysyłania zapytań typu HTTP do
serwera (czyli AJAX), zaczęto używać funkcji zwrotnych (ang. callback) aby wywoływać kod jak już dane będą
dostępne. Takie same funkcje używa się też w funkcji setTimeout
. W miarę pisania coraz bardziej skomplikowanych
aplikacji można było wpaść w pułapkę tzw. piekła funkcji zwrotnych (ang. callback hell). Przykład takiego kodu:
W powyższym kodzie użyto tylko pięciu funkcji zwrotnych, ale przy bardziej skomplikowanym kodzie może być ich więcej.
Rozwiązaniem tego problemu były obiekty typu Promise
, czyli obietnice, które zawierają wartość, która zostanie
dostarczona w przyszłości (można także utworzyć ten obiekt z natychmiastową wartością, ona także będzie
asynchroniczna). Obiekty te są częścią ECMAScript w wersji 6.
Pierwszy raz spotkałem się z obietnicami, poprzez jeden z pierwszych frameworków JavaScript, czyli Dojo toolkit (ostatnio wydano nową wersje 2.0 pod nazwą dojo), który posiadał funkcje, konstruktor Deferred. Był to chyba pierwszy framework, który dodał ten obiekt (jeśli znasz inną bibliotekę/framework, która posiadała obiekty defered przed dojo, nawet w innym języku, to pisz w komentarzu). Było to lata przed tym jak powstały jQuery i Angular. Napisałem nawet, dawno temu, tutorial na temat dojo toolkit.
Aby utworzyć obiekt typu Promise
, trzeba użyć konstruktora, o takiej właśnie nazwie, do którego przekazujemy funkcję z dwoma
argumentami, które także są funkcjami. Po wywołaniu, spełnią obietnice lub ją odrzucają.
Aby otrzymać wartość z obiektu obietnicy, należy użyć funkcji then
, przekazując do niej funkcje, której argumentem będzie
wartość obietnicy.
Obietnice nie pozbywają się funkcji zwrotnych, ale za ich pomocą można „spłaszczyć” zagnieżdżone funkcje. Poniżej pierwszy przykład zapisany za pomocą obietnic.
Kod trochę się skomplikował, ponieważ mieliśmy dwie tablice z użytkownikami oraz produktami, przykład z funkcjami zwrotnymi był o wiele czytelniejszy, ale to tylko przykład. Pierwsza funkcja then jest jednak dość czytelna, a w następnej mamy już dostęp do tablicy dwuelementowych tablic, gdzie pierwszy element to użytkownik a drugi do tablica produktów.
Fajną funkcją obietnic jest to, że możemy użyć funkcji reduce
, aby „zwinąć” listę produktów do postaci
pojedynczej liczby i nie potrzebujemy już sprawdzać, czy funkcja jest ostatnią w tablicy.
Aby uzyskać równoległe wywołanie wszystkich funkcji getPrice
i getQuantity
można wywołać map
a następnie reduce
.
Zapisanie równoległe pierwszego przykładu, z użyciem funkcji zwrotnych, dodatkowo pogmatwałoby ten kod.
Inną fajną cechą obietnic jest dodawanie obsługi błędów. Jeśli chcielibyśmy dodać ich obsługę do pierwszego
przykładu, nasz kod jeszcze bardziej by się skomplikował, ponieważ musielibyśmy dodawać do każdej
funkcji drugą, która wywołałaby się w przypadku błędu lub tak jak w przypadku node.js przekazywać błąd jako pierwszy
argument lub null w przypadku jego braku. Aby funkcja catch
się wywołała, wystarczy w dowolnej funkcji wywołać
reject
lub wyrzucić wyjątek. Dzięki temu będziemy mieli tylko jedno miejsce obsługi błędów. Nie musimy też dodawać
try..catch ponieważ wszystkie wyjątki, nawet te z silnika JavaScript, jak type
albo range
error
, także trafią do
funkcji catch.
Obiekty typu Promise
(obietnice) zostały zaimplementowane w większości przeglądarek (oprócz IE). Aby zobaczyć,
które wersje przeglądarek zaimplementowały to API możesz zerknąć na
stronę MDN lub
na tabelę poszczególnych funkcjonalności es6.
Inna nowość w ECMAScript to funkcja fetch, której API bazuje na obietnicach. Zastępuje ona obiekt XMLHttpRequest i udostępnia prostsze API.
Funkcja fetch jest zaimplementowana w prawie wszystkich przeglądarkach oprócz IE
oraz Opera mini. Aby użyć kodu, który korzysta z funkcji fetch
w przeglądarkach, które nie zaimplementowały tego API,
można skorzystać implementacji zastępczej (ang. polyfill) napisanej przez firmę GitHub.
Fetch można także używać w node.js, poprzez dwa pakiety npm: node-fetch lub whatwg-fetch.
Komentarze
Hasło, które podasz umożliwi ponowne zalogowanie się i np. usunięcie komentarza, jest dobrowolne. Email jest szyfrowany i używany do wysyłania powiadomień o odpowiedziach do komentarzy oraz do pobierania awatara dzięki usłudze Gravatar.com.