Angular - operatory RxJs

Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 6155 razy

Operator of

Ten operator tworzy typ Observable z zwykłych zmiennych podanych jako jego argumenty. Oto przykład:

const value: number = 10; of(value, 20).subscribe((val) => console.log('value: ', val));

Wynik działania powyższego kodu:

value: 10
value: 20

Operator interval

Jeżeli chcesz co określony interwał czasowy wykonać jakieś zadanie to operator interval jest tym czego szukasz. Pamiętać należy jednak, że każda subskrypcja do utworzonej instancji obiektu obserwatora wymaga odsubskrybowania. Dzieje się tak dlatego, że operator interval tworzy obserwatora, który po subskrypcji jest wywoływany cały czas i istnieje tak długo, jak długo się nie odsubskrybujesz. Oto przykład użycia tego operatora.

interval(100).pipe( take(5) // ograniczam działanie do 5 pierwszych otrzymanych wartości z kolejnych wywołań metody next obserwatora ).subscribe( (value) => console.log('Interval: ', value) );

Wynik działania powyższego kodu:

Interval: 0
Interval: 1
Interval: 2
Interval: 3
Interval: 4

Operator timer

Z kolei ten operator umożliwia stworzenie operatora, który po określonym czasie wyemituje pierwszą wartość. Następne może emitować co określony w drugim parametrze interwał czasowy, jeżeli ten został podany, jeżeli nie to subskrypcja się kończy. W przeciwnym przypadku obiekt staje się nieskończonym obserwatorem, którego przerwanie działania wymaga odsubkrybowania. Oto przykład użycia tego operatora:

timer(1000).subscribe((value) => console.log('Timer: ', value));

Wynik działania w konsoli przeglądarki:

Timer: 0

Operator from

Operator from zamienia typ:

na typ Observable. Elementy tablic, stringów czy innych iterowalnych typów są emitowane oddzielnie. Oto przykład:

from([100, 200, 300]).subscribe((value) => console.log('Value from array converted to observable:', value));

Wynik działania w konsoli przeglądarki:

Value from array converted to observable: 100
Value from array converted to observable: 200
Value from array converted to observable: 300

Operator fromEvent

Możliwe jest oczywiście utworzenie obiektu Observable z zdarzenia za pomocą operatora fromEvent w następujący sposób:

let subscriber: Subscription = fromEvent(document, 'click').subscribe((event) => console.log('Click event:', event));

Po kliknięciu powinno pojawić się w konsoli coś w tym stylu:

Click event: 
click { target: div.ng-untouched.ng-pristine.ng-valid, buttons: 0, clientX: 1243, clientY: 263, layerX: 1243, layerY: 263 }

Dla każdej subskrybcji konieczne jest wykonanie opercacji odsubskrybowania sie, aby uniknąć wycieków pamięci.

Operator map

Operator map umożliwia mapowanie zwracanej w subscrib-ie wartości dla funkcji wywoływanej przy pomyślnym zasubskrybowaniu się. Oto przykład wykorzystania tego operatora:

const value = of(1, 2, 3); value.pipe( map((val: number) => val * 2) ).subscribe((val: number) => console.log(val));

Wynik działania powyższego kodu widoczny w konsoli przeglądarki będzie następujący:

2
4
6

Jak widać przed subskrypcją dane w operatorze map zostały zmodyfikowane i zwrócone w subscribie.

Operator switchMap

Marzy ci się możliwość przełączenia się z jednego subscribea na innego? No problemos amigos! Albowiem wystarczy użyć w tym celu operatora switchMap w następujący sposób:

of('First observable data').pipe( switchMap(() => of('Second observable data')) ).subscribe( (value: string) => console.log(value) );

Wynik działania powyższego kodu w konsoli przeglądarki będzie wyglądał następująco:

Second observable data

Operator switchMapTo

Ten operator działa podobnie jak poprzedni, z tą różnicą, ze przyjmuje jako argument nie funkcję zwracającą Observable, ale sam obiekt Observable:

of('First observable data').pipe( switchMapTo(of('Second observable data')) ).subscribe( (value: string) => console.log(value) );

Wynik działania taki sam jak poprzednio, czyli:

Second observable data

Operator concat

Za pomocą tego operatora można wykonać wiele subskrypcji z zachowaniem ich kolejności. Wartości zwracane są oddzielnie, ale można je zabrać w następujący sposób:

let values: any[] = []; concat( of(10, 20, 30).pipe( delay(1000) ), of('some data'), of({name: 'Grzegorz', surname: 'Brzęczyszczykiewicz'}) ) .subscribe( (value) => { console.log('Values from concat:', value); values.push(value); }, (err) => { console.log('error: ', err); values = []; // błąd więc wywalam wszystkie dane }, () => { console.log('Finito! All values are collected: ', values); } );

Wynik działania powyższego kodu:

Values from concat: 10
Values from concat: 20
Values from concat: 30
Values from concat: some data
Values from concat: 
Object { name: "Grzegorz", surname: "Brzęczyszczykiewicz" }
Finito! All values are collected:  
Array(5) [ 10, 20, 30, "some data", {...} ]

Jak widać po zakończeniu subskrypcji otrzymywane są dane, jedyny problem jest w tym, że trzeba jeszcze sprawdzić, czy błędu po drodze nie było, bo jak był to nie wszystkie dane zostały zebrane.

Jeżeli w trakcie wykonywania jakiegoś subscriba zwrócony zostanie błąd, wtedy do ostatnia metoda nie zostanie wywołana, a jedynie dwa błędy szczegółowy dotyczący danego obserwatora i ogólny dla zbioru zapytań.

Operator toArray

Ten operator umożliwia zwrócenie wszystkich odpowiedzi w formie tablicy. Oto przykład z zmodyfikowanym kodem z użycia operatora concat:

concat( of(10, 20, 30).pipe( delay(1000) ), of('some data'), of({name: 'Grzegorz', surname: 'Brzęczyszczykiewicz'}) ).pipe( toArray() // zamiana danch na tablicę ){ .subscribe( (value) => { console.log('Values from concat & toArray operators:', value); values.push(value); } );

Wynik działania powyższego kodu:

Values from concat & toArray operators: 
Array(5) [ 10, 20, 30, "some data", {...} ]

Operator forkJoin

Ten operator umożliwia wykonanie wielu subskrypcji i zwraca ich wartości w postaci tablicy dopiero po ich pomyślnym zakończeniu. Elementy tejże tablicy odpowiadają kolejności wywołań metod zwracających Observable ułożonych w tablicy jedynego parametru tego operatora. Oto przykład:

forkJoin( [ of(10), of({ id: 100, name: 'Grzegorz', surname: 'Brzęczyszczykiewicz' }) ]) .subscribe(([value1, value2]) => { console.log(value1); console.log(value2); });

Wynik działania powyższego kodu w konsoli przeglądarki:

10
Object { id: 100, name: "Grzegorz", surname: "Brzęczyszczykiewicz" }

Operator tap

Jeżeli marzy ci się po nocach (tak jak kiedyś mnie) aby zanim jeszcze się zasubskrybujesz zrobić coś ekstra w kodzie, to nie martw się albowiem z odsieczą nadchodzi operator tap, który niczym dobry przyjaciel wyciąga przyjazną rękę ku tobie, abyś mógł spełnić swe marzenia senne. Czyniąc długą historię krótką, istnieje kawałek kodu, który to potwierdzi:

const valueToSet: number[] = []; of(1, 2, 3).pipe( tap((val: number) => valueToSet.push(val * 2)) ).subscribe((val: number) => { console.log('Value: ', val); console.log('valueToSet', valueToSet); });

Wynik działania powyższego kodu:

Value:  1
valueToSet 
Array [ 2 ]
Value:  2
valueToSet 
Array [ 2, 4 ]
Value:  3
valueToSet 
Array(3) [ 2, 4, 6 ]

Operator startWith

Subskrybujesz się na strumień, ale chcesz aby pierwszą wartością, jaką otrzymasz była sprecyzowana przez ciebie wartość? Nie ma sprawy, operator startWith załatwi to za ciebie:

of(1, 2, 3, 4, 5).pipe( startWith(10) ).subscribe((value: number) => console.log(value));

A oto i rezultat działania powyższego kodu:

10
1
2
3
4
5

Chcesz dodać więcej wartości? Daj kurze grzędę, nie wyżej siędę! Dobra nie takie rzeczy RxJs potrafi robić:

of(1, 2, 3, 4, 5).pipe( startWith(10, 2) ).subscribe((value: number) => console.log(value));

Zaskakujący wynik działania powyższego kodu:

10
2
1
2
3
4
5

Operator endWith

Operator endWith robi dokładnie to samo co operator startWith tylko, że na odwrót. Oto kawałek kodu, który to obrazuje:

of(1, 2, 3, 4, 5).pipe( endWith(10, 2) ).subscribe((value: number) => console.log(value));

Wynik działania powyższego kodu:

1
2
3
4
5
10
2

Operator filter

Jak nie trudno się domyślić ten jakże przydatny operator RxJs umożliwia filtrowanie przychodzących danych według dowolnych kryteriów. A oto i przykład jego użycia:

of( {name: 'Grzegorz', surname: 'Brzęczyszczykiewicz'}, {name: 'Donald', surname: 'Tusk'}, {name: 'Adam', surname: 'Mickiewicz'} ).pipe( filter((value: any) => { if (value.name !== 'Donald' && value.surname !== 'Tusk') { return true; } console.log('A tego nie wpuszczamy:', value); return false; }) ).subscribe((value) => console.log('value from filter', value))

I wynik działania powyższego kodu:

value from filter 
Object { name: "Grzegorz", surname: "Brzęczyszczykiewicz" }
A tego nie wpuszczamy: 
Object { name: "Donald", surname: "Tusk" }
value from filter 
Object { name: "Adam", surname: "Mickiewicz" }

Operator skip

Jeżeli chcesz pominąć określoną liczbę emisji subskrajba to operator skip ci to umożliwi. Oto przykładowy kod:

of(1, 2, 3, 4, 5).pipe( skip(2) // opuszczenie dwóch pierwszych wartości ).subscribe((value) => console.log('After skip operator:', value));

Wynik działania wyświetlony w konsoli przeglądarki:

After skip operator: 3
After skip operator: 4
After skip operator: 5

Operator skipUntil

Jeżeli pragniesz lub (co gorsza) śni ci się po nocach możliwość rozpoczęcia emisji jednego subscriba na emisję innego to operator skipUntil ci to umożliwi:

const subscribe = interval(1000) .pipe(skipUntil(timer(6000))) .subscribe(val => console.log('Interval values:', val));

Po 6 sekundach emisja zostanie zakończona. Oto wynik wyświetlony w konsoli przeglądarki:

Interval values: 6
Interval values: 7
Interval values: 8
Interval values: 9
Interval values: 10
...

Ponieważ interval zwraca obserwatora, który emituje wartości w nieskończoność konieczne jest odsubskrybowanie się, aby nie było wycieków pamięci.

Operator skipWhile

Ten operator umożliwia opuszczenie wszystkich emitowanych elementów, do momentu spełnienia warunku. Oto przykład:

of(1, 2, 3, 4, 5) .pipe(skipWhile( (value) => value < 3 )) .subscribe((value) => console.log('Emitted values after skipWhile operator', value));

Wynik działania powyższego kodu wygląda następująco:

Emitted values after skipWhile operator 3
Emitted values after skipWhile operator 4
Emitted values after skipWhile operator 5

Operator take

Operator take pobiera z strumienia danych tylko podaną przez użytkownika liczbę pierwszych wywołań. Oto przykład działania:

of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).pipe( take(3) ).subscribe((value) => console.log('value from take:', value));

Wynik działania w konsoli przeglądarki:

value from take: 1
value from take: 2
value from take: 3

Operator takeLast

Ten operator zwraca podaną mu jako parametr liczbę elementów. Oto przykład:

of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).pipe( takeLast(3) ).subscribe((value) => console.log('value from takeLast:', value));

I wynik działania powyższego kodu w konsoli przeglądarki:

value from takeLast: 8
value from takeLast: 9
value from takeLast: 10

Operator takeWhile

Operator ten umożliwia pobieranie danych do momentu, gdy napotkana wartość spełniaja warunek zwracany przez podaną na wejście funkcję przyjmującą jako argument wyjście obserwowanego strumienia danych. Oto przykład działania:

of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).pipe( takeWhile((value: number) => value < 4 ) ).subscribe((value) => console.log('value from takeWhile:', value));

A zaskakujący wynik działania powyższego kodu wygląda następująco:

value from takeWhile: 1
value from takeWhile: 2
value from takeWhile: 3

Operator takeUntil

A więc takeUntil jest operatorem umożliwiającym ograniczenie pobierania danych do momentu zmiany stanu innego obserwatora. Oto przykład:

const source = interval(1000); const timer$ = timer(5000); const subscribe = source.pipe(takeUntil(timer$)) .subscribe(val => console.log('value from takeUntil:', val));

Co sekundę będzie wyświetlane w konsoli to:

value from takeUntil: 0
value from takeUntil: 1
value from takeUntil: 2
value from takeUntil: 3

Dopóki nie przyjdzie pierwszy callback z strumienia utworzonego za pomocą operatora Timer, czyli po pięciu sekundach.

Strony powiązane
strony powiązane
  1. learnrxjs.io/operators/ - strona dokumentacji z spisem operatorów RxJs
Propozycje książek