Kategorie
Transkrypcje YouTube

4 zaawansowane operatory do Higher Order Streamów #RxJS

🔴 Bez tych operatorów nie możesz mówić, że znasz RxJS! W tej lekcji tłumaczę jak działa: concatAll, concatMap, switchAll, switchMap, exhaustAll, exhaustMap, mergeAll, mergeMap. Trochę tego jest, prawda? Wszystko pokazane na matrycy, którą tworzyliśmy w poprzednich odcinkach o RxJS. Zapraszam!

Kod do odcinka – Pull Reuqest:
https://github.com/lebrande/rxjs-higher-order-streams/pull/3

Nowa wersja RxJS 7

TLDR: Jeśli nie interesuje Cię jak zmigrować z wersji 6 na 7, to przejdź do: Zaawansowane operatory do Higher Order Streamów.
Niedawno wyszedł RxJS w wersji 7, a my w naszym projekcie cały czas mamy 6. Zatem pierwszą rzeczą będzie podbitka wersji. Pierwsza na myśl przychodzi do głowy komenda ‘npm update’, jest taka. Jednak tym sposobem możesz podbić wersję minor i patch, czyli to co jest po kropkach.

Ja chcę jednak podbić wersję major z 6 na 7. Jak to zrobić? Najprościej jest moim zdaniem zainstalować rxjs jeszcze raz, ale ze wskazaniem konkretnej wersji po małpce: npm i rxjs@7

Co nas zaskoczy w siódemce?

Przejdźmy na stronę https://rxjs.dev/ zobaczmy raport o tym co się zmieniło. Już na stronie głównej otrzymuję baner 'VERSION 7 RELEASED’.

Klikając w banner przechodzę do raportu. Szukam rzeczy które dotyczą tego czym się zajmowaliśmy lub będziemy zajmować za chwilę.
Jest 'map’ – tutaj zmienia się coś w kontekście this, ale my go nie używamy.
Jest też 'take’ i tutaj dostaję informację, że take wyrzuci błąd dla argumentów ujemnych i NaN.
I to w zasadzie tyle jeśli chodzi o API. Nie ma żadnych zmian, które by nas dotyczyły. Mogę zatem spokojnie użyć wersji siedem.

Zaawansowane operatory do Higher Order Streamów

Przejdziemy teraz do kodu. Mam tutaj stan z poprzedniego odcinka, ale usunąłem wykomentowany kod. Dla porządku.

mergeAll

Pierwszym operatorem jest użyty już mergeAll. Zwróć uwagę jak zachowuje się matryca. Przy każdym kolejnym kliknięciu wypuszczany jest nowy wiersz klocków. Jak szybko klikam, to powstaje taka fala. Zauważ, że klocki generują się niezależnie od siebie w każdym wierszu.
Mówi: zapraszam wszystkie grupy (wiersze) razem.

concatAll

Teraz chciałbym, aby każdy kolejny wiersz, zaczynał się renderować dopiero, gdy jego poprzednik skończy swoją robotę. Kolejne wiersze będą czekać na siebie. Użyję operatora concatAll. Emituje on z kolejnego strumienia dopiero, kiedy poprzedni strumień (wiersz), się zakończy. Wypuszcza kolejne wiersze po jednym. Zwróć też uwagę, że wszystkie kliknięcia, grzecznie stoją w kolejce, są zapamiętywane przez strumień. Jak kliknę szybko 5 razy z rzędu, to po pewnym czasie wyrenderuje się 5 wierszy. Od razu odnoszę wrażenie, że wszystko dzieje się wolniej.
Mówi: nie wszyscy na raz, proszę pojedynczo, dla każdego mam 7 minut (klocków). Możesz to porównać do sytuacji w kolejce do lekarza.

switchAll

W następnym przypadku chcę przyspieszyć, ale nadal renderować po jednym wierszu. Kiedy kliknę drugi i każdy kolejny raz, aktualny wiersz ma zostać przerwany i zacząć się następny. Doprowadzi to do sytuacji, że niektóre wiersze będą niepełne. Taki stream będzie ignorował pewne elementy. Jest to jeden z najbardziej przydatnych operatorów w rxjs. Pozwala on na optymalizację aplikacji. Jest na tyle sprytny, że jeśli użyjesz go z ajax, to żądanie HTTP zostaje automatycznie anulowane!

exhaustAll

W naszej matrycy ciężko mi będzie znaleźć opowieść dla operatora exhaustAll. Dlatego wyjdę od odniesienia do żądań HTTP. Jeśli wyobrażę sobie, że każdy wiersz (kliknięcie) to request do serwera, to powiem: niech wykona się request do końca, ale w tym czasie każdy kolejne kliknięcie będzie ignorowane w całości. Jeśli kliknę szybko 5 razy, to wyrenderuje się jeden wiersz do końca i koniec. Następnie klikam raz jeszcze i widzę, że 4 kolejne zostały całkowicie pominięte i pojawiają się kolejne klocki w wierszu szóstym (y: 5).

Skrótowe wersje wszystkich wymienionych operatorów

Okazuje się, że moja konstrukcja jest na tyle powszechna, że jest dla niej skrót. Można połączyć każdy z wymienionych wyżej operatorów z operatorem map. Wystarczy podmienić końcówkę All na Map.
Zamiast:

const tiles$ = rows$.pipe(
  map((y) => columns$.pipe(
    map((x) => [x, y] as Coordinates),
  )),
  switchAll(),
);

Mogę skrócić do:

const tiles$ = rows$.pipe(
  switchMap((y) => columns$.pipe(
    map((x) => [x, y] as Coordinates),
  )),
);

Oto lista wszystkich:
– mergeAll -> mergeMap
– concatAll -> concatMap
– switchAll -> switchMap
– exhaustAll -> exhaustMap