Software Development

More reactive Angular

6 czerwca, 2022 0
Podziel się:

W dzisiejszym artykule przybliżę temat Reactive Extensions – skutecznego narzędzia do rozwiązywania określonych klas problemów, choć niekoniecznie wszystkim dobrze znanego.

Co to jest Reactive Extensions?

Autorzy opisują Reactive Extensions (lub ReactiveX, Rx) jako API do programowania asynchronicznego z użyciem obserwowalnych strumieni (Observable streams). Jest ono dostępne dla kilku różnych języków programowania m.in.:

  • Java,
  • JavaScript,
  • C#,
  • C++,
  • Scala,
  • PHP,
  • Python,
  • Go,
  • Dart i innych.

W Angular wykorzystywana jest implementacja RxJS. Jak sama nazwa wskazuje, jest to wersja dla JavaScript.

O ile programowanie reaktywne (reactive programming), może być bardziej znane, to dla kogoś, kto zetknął się z Rx po raz pierwszy, ‘observable streams’ może brzmieć dość tajemniczo.

Właściwości Rx sprawiają, że są one bardzo skuteczne do rozwiązywania określonych klas problemów. Jednak, zaczynając od początku, programowanie reaktywne polega na asynchronicznym, nieblokującym przetwarzaniu danych i reagowaniu na zmiany w tych danych.

Gdy tylko pojawią się zmiany w strumieniu danych, aplikacja reaguje na te zmiany, co jest bardzo pomocne w dynamicznie zmieniających się interfejsach i aplikacjach.

Strumienie w programowaniu to ciąg danych przychodzących w czasie o nieokreślonej długości. Strumień może być skończony np. żądanie AJAX zwracające jeden element lub nieskończony np. aktualna pozycja kursora.

Observable streams

Observable stream to po prostu strumień danych ze specjalnymi własnościami. Poza zwykłymi elementami – danymi, które mogą być typem prymitywnym albo złożonym obiektem. Observable stream może wysyłać dwa dodatkowe typy danych:

  • błąd,
  • znacznik końca, gdy już wszystkie elementy zostały wysłane (podobieństwo do wzorca Iteratora).

Taki strumień można obserwować (subskrybować), aby odebrać zwrócone elementy w celu dalszego przetworzenia (wzorzec obserwatora).

Reactive Extensions to połączenie zalet m.in. wzorców obserwatora, iteratora i programowania funkcyjnego.

Observable streams są jak funkcje w programowaniu funkcyjnym. Mogą być argumentami dla innych strumieni (high order streams), mogą być łączone, a na elementach mogą być przeprowadzane różne operacje np. filtrowanie lub mapowanie. Zestaw wbudowanych operatorów jest spory, co niewątpliwie jest mocną stroną Rx.

Dlaczego warto korzystać z Reactive Extensions?

Rozwiązania zastosowane w Rx są szczególnie przydatne przy wielu źródłach zdarzeń i skomplikowanej logice między nimi. Implementacja obsługi takiego strumienia jest taka sama – niezależnie, czy strumień będzie składał się z jednego, kilku, czy nieskończenie wielu elementów. Elementy strumienia mogą być przetwarzane podobnie jak skończone kolekcje np. tablice.

W Angular Observable streams są używane do wielu asynchronicznych operacji:

  • komunikacji między komponentami,
  • zarządzania i synchronizacji pomiędzy żądaniami i odpowiedziami AJAX w module http,
  • zarządzania routingiem i formularzami, nasłuchując i reagując na zdarzenia od użytkownika.

RxJS vs Promises

W przeciwieństwie do Promisów Observable streams mają następujące cechy (zalety):

  • pozwalają obsługiwać więcej niż jeden event,
  • wywołanie jest ‘lazy’ i dzieje się w momencie subskrybowania, a nie tworzenia,
  • może je anulować/ponawiać,
  • dostarczają wielu operatorów pozwalających na operacje na na strumieniach i danych.

Z tego względu w Angular 2 zastosowano Observable streams w module Http zamiast wcześniej stosowanych Promisów.

W jaki sposób to działa?

Przejdźmy do przykładu. Dla uproszczenia nie skorzystam z formularzy w Angular.

1. Punktem wyjściowym będzie komponent, w którym Rx jest używany jedynie wewnętrznie przez HttpClient. Należy pamiętać, że każdą zdefiniowaną przez nas subskrypcję Observable stream należy zakończyć przy niszczeniu komponentu, aby uniknąć wycieku pamięci. Nie dotyczy to strumieni z HttpClient, ponieważ po otrzymaniu elementu lub błędu wysyłany jest znak końca strumienia.

Komponent jest napisany w stylu imperatywnym. Ciąg instrukcji został krok po kroku zdefiniowany przez programistę. Po zasubskrybowaniu otrzymane dane przypisujemy do zmiennej, a potem je przekształcamy.

Tutaj możesz zobaczyć, jak wyglądało moje pierwsze podejście do Angulara, gdy nie wiedziałem nic o Rx.

2. Kolejne kroki będą przejściem od programowania imperatywnego do programowania deklaratywnego. W tym kroku zmieniamy podejścia do definiowania danych potrzebnych do wyświetlenia w template. Zamiast modyfikować dane otrzymane z zapytania http, definiujemy Observable stream, który wykorzystuje strumień bazowy oraz modyfikuje przychodzące dane. W ten sposób nie zarządzamy ciągiem instrukcji, którym mają być poddane przychodzące dane, a definiujemy kształt (typ) danych, które chcemy otrzymać.

3. Zdefiniowane strumienie przypisujemy do zmiennych. Powszechną praktyką jest dodawanie znaku $ na końcu nazwy zmiennej w celu oznaczenia, że jest to Observable stream.

4. Kolejnym krokiem będzie separacja logiki odpowiedzialnej za pobieranie danych do serwisu.

5. Usuwamy zmienne z danymi i zostawiamy tylko zdefiniowane wcześniej Observable streams. Nie subskrybujemy strumieni w komponencie. Używamy strumieni w template używając ‘async’ pipe. Dzięki temu subskrypcją i jej zakończeniem zarządza za nas Angular.

6. Cieszymy się czytelnym i łatwym w utrzymaniu kodem. Przykład nie jest skomplikowany. W miarę rosnącego skomplikowania zależności pomiędzy danymi, elementami interfejsu i akcjami użytkownika, korzyści płynące z używania Rx są coraz bardziej widoczne.

Podsumowanie

Koncepcja reactive programming oraz implementacja Reactive Extensions nie jest ściśle związana z Angular ani żadnym konkretnym językiem programowania. Jest to rozwiązanie pewnej klasy problemów, które pojawiają się zarówno w aplikacjach frontendowych jak i backendowych, niezależnie od stosowanej technologii. Z powodzeniem można używać RxJS z VanillaJS.

Więcej o Reactive Extensions dowiesz się z:

Sławomir Cesarz
Autor: Sławomir Cesarz
Sławek rozpoczął swoją karierę w IT ponad 7 lat temu jako tester manualny, a później pisząc testy automatyczne dla branży medycznej. Po tej krótkiej przygodzie skierował się w stronę developerską na warstwie frontendowej aplikacji, przechodząc po wielu domenach – począwszy od branży finansowej, przez retail, a na branży medycznej kończąc. Obecnie ukierunkowany na projekty realizowane w JavaScript z ujęciem Reacta, Angulara i TypeScripta. Po pracy rozwija swoje umiejętności manualne w zakresie strugania. Niecodzienna pasja pozwala mu na tworzenie rzeźb w drewnie 😊

    Imię i nazwisko (wymagane)

    Adres email (wymagane)

    Temat

    Treść wiadomości

    Zostaw komentarz