{"id":29889,"date":"2023-03-01T13:26:00","date_gmt":"2023-03-01T12:26:00","guid":{"rendered":"https:\/\/nearshore-it.eu\/artykuly\/operator-wyzszego-rzedu-rxjs\/"},"modified":"2024-11-07T14:22:34","modified_gmt":"2024-11-07T13:22:34","slug":"operator-wyzszego-rzedu-rxjs","status":"publish","type":"post","link":"https:\/\/nearshore-it.eu\/pl\/artykuly\/operator-wyzszego-rzedu-rxjs\/","title":{"rendered":"Higher-Order Observable Mapping w\u00a0RxJS"},"content":{"rendered":"\n<div class=\"table-of-contents\">\n    <p class=\"title\"><\/p>\n    <ol>\n                    <li><a href=\"#Observable\">1.  Observable oraz strumie\u0144 danych <\/a><\/li>\n                    <li><a href=\"#Operatory-w-RxJS\">2.  Operatory w RxJS<\/a><\/li>\n                    <li><a href=\"#Switchmap\">3.  SwitchMap<\/a><\/li>\n                    <li><a href=\"#Mergemap\">4.  MergeMap<\/a><\/li>\n                    <li><a href=\"#Contactmap\">5.  ContactMap<\/a><\/li>\n                    <li><a href=\"#exhaustmap\">6.  ExhaustMap<\/a><\/li>\n                    <li><a href=\"#faq\">7.  FAQ<\/a><\/li>\n            <\/ol>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"Observable\">Observable oraz strumie\u0144 danych<\/h2>\n\n\n\n<p>Jednymi z najwa\u017cniejszych element\u00f3w biblioteki RxJS s\u0105 Observable oraz strumienie danych.<\/p>\n\n\n\n<p>Oba te poj\u0119cia s\u0105 podobne, jednak wyst\u0119puj\u0105 mi\u0119dzy nimi subtelne r\u00f3\u017cnice:<\/p>\n\n\n\n<figure class=\"wp-block-table aligncenter is-style-stripes\"><table><thead><tr><th><strong>Strumienie danych<\/strong>&nbsp;&nbsp;<\/th><th><strong>Observable<\/strong>&nbsp;<\/th><\/tr><\/thead><tbody><tr><td>Strumienie danych s\u0105 reprezentowane przez klas\u0119 Observable w bibliotece RxJS.&nbsp;<\/td><td>Observable mo\u017ce te\u017c reprezentowa\u0107 pojedyncze warto\u015bci, a nie tylko strumienie.&nbsp;<\/td><\/tr><tr><td>Maj\u0105 w\u0119\u017cszy zakres i pozwalaj\u0105 na manipulacje na danych i kontrolowanie ich w ograniczony spos\u00f3b.&nbsp;<\/td><td>Ma szerszy zakres zastosowa\u0144 ni\u017c strumienie danych, poniewa\u017c pozwalaj\u0105 na manipulowanie strumieniami i kontrolowanie ich w bardziej zaawansowany spos\u00f3b.&nbsp;&nbsp;&nbsp;<\/td><\/tr><tr><td>Strumienie danych nie pozwalaj\u0105 na multipleksowanie, \u0142\u0105czenie, filtrowanie i mapowanie danych.&nbsp;<\/td><td>Observable pozwala na wykonanie pewnych operacji, takich jak multipleksowanie, \u0142\u0105czenie, filtrowanie i mapowanie, co pozwala na bardziej zaawansowan\u0105 prac\u0119 z danymi.&nbsp;&nbsp;&nbsp;<\/td><\/tr><tr><td>Strumienie danych to sekwencje warto\u015bci, kt\u00f3re s\u0105 emitowane przez \u017ar\u00f3d\u0142o.&nbsp;<\/td><td>Observable to obiekt, kt\u00f3ry s\u0142u\u017cy do zarz\u0105dzania strumieniem danych.&nbsp;&nbsp;&nbsp;<\/td><\/tr><tr><td>Nie mo\u017cna za ich pomoc\u0105 kontrolowa\u0107 czasu przep\u0142ywu warto\u015bci czy sterowa\u0107 b\u0142\u0119dami.&nbsp;<\/td><td>Ma dodatkowe cechy pozwalaj\u0105ce np. na kontrolowanie czasu przep\u0142ywu warto\u015bci lub sterowanie b\u0142\u0119dami. &nbsp;&nbsp;<\/td><\/tr><tr><td>Strumienie danych s\u0105 sekwencjami warto\u015bci emitowanymi przez \u017ar\u00f3d\u0142o.&nbsp;<\/td><td>Observable to obiekt, kt\u00f3ry zarz\u0105dza strumieniami danych i pozwala na manipulowanie nimi.&nbsp;<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p>Podsumowuj\u0105c, Observable maj\u0105 szerszy zakres zastosowa\u0144 ni\u017c strumienie danych i maj\u0105 dodatkowe funkcje, pozwalaj\u0105ce na kontrolowanie czasu przep\u0142ywu warto\u015bci i sterowanie b\u0142\u0119dami.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Operatory-w-RxJS\">Operatory w RxJS<\/h2>\n\n\n\n<p>Prawdziw\u0105 pot\u0119g\u0119 biblioteki RxJS stanowi\u0105 operatory. Operatory pozwalaj\u0105 przekszta\u0142ca\u0107, filtrowa\u0107, \u0142\u0105czy\u0107 strumienie danych i zarz\u0105dza\u0107 nimi. RxJS dostarcza szereg operator\u00f3w, takich jak: map, filter, reduce, debounceTime, distinctUntilChanged itp., kt\u00f3re pozwalaj\u0105 na przetwarzanie danych w strumieniach. Wyb\u00f3r odpowiedniego operatora jest wa\u017cny, gdy\u017c \u017ale dobrany operator mo\u017ce wp\u0142yn\u0105\u0107 na funkcjonowanie systemu. Ni\u017cej omawiam najwa\u017cniejsze z nich.<\/p>\n\n\n\n<p><strong>Przeczytaj tak\u017ce:<\/strong> <a href=\"https:\/\/nearshore-it.eu\/pl\/artykuly\/programowanie-reaktywne-w-js-z-rxjs\/\">Programowanie reaktywne w JavaScript z RxJS<\/a><\/p>\n\n\n\n<p><strong>Higher-Order Observable Mapping<\/strong><\/p>\n\n\n\n<p>Biblioteka RxJS zawiera szczeg\u00f3lny typ operator\u00f3w, tzw. <strong>higher-order operators<\/strong>, czyli operatory wy\u017cszego rz\u0119du, kt\u00f3re pozwalaj\u0105 na z\u0142o\u017cone manipulowanie strumieniami danych. Higher-order operators to operatory, kt\u00f3re zawieraj\u0105 w argumentach inne operatory lub Observable i zwracaj\u0105 nowe Observable maj\u0105ce zastosowanie do pierwotnego strumienia danych.<\/p>\n\n\n\n<p>Istnienie higher-order operators w bibliotece RxJS jest uzasadnione z kilku powod\u00f3w:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Zapewniaj\u0105 one prostsze i bardziej czytelne sposoby manipulowania strumieniami danych. <\/strong>Dzi\u0119ki nim mo\u017cna z\u0142o\u017cy\u0107 wiele operacji na strumieniu w jeden \u0142a\u0144cuch, co u\u0142atwia czytanie i zrozumienie kodu.<\/li>\n\n\n\n<li><strong>Umo\u017cliwiaj\u0105 bardziej elastyczne manipulowanie strumieniami danych. <\/strong>Wiele higher-order operators pozwala na dynamiczne tworzenie nowych strumieni danych w zale\u017cno\u015bci od zdarze\u0144 zachodz\u0105cych w pierwotnym strumieniu. Dzi\u0119ki temu mo\u017cna \u0142atwo dostosowa\u0107 przetwarzanie danych do zmieniaj\u0105cych si\u0119 wymaga\u0144.<\/li>\n\n\n\n<li><strong>Higher-order operators pozwalaj\u0105 na wielokrotne wykorzystanie kodu.<\/strong> Wiele operacji na strumieniach danych jest podobnych i mo\u017cna je zastosowa\u0107 w wielu miejscach w aplikacji. Higher-order operators u\u0142atwiaj\u0105 u\u017cycie tych samych operacji w r\u00f3\u017cnych cz\u0119\u015bciach kodu, co pozwala na unikni\u0119cie powt\u00f3rze\u0144.<\/li>\n<\/ul>\n\n\n\n<p>Podsumowuj\u0105c, higher-order operators w bibliotece RxJS pozwalaj\u0105 na bardziej elastyczne, czytelne i wielokrotne wykorzystanie kodu do manipulowania strumieniami danych. Dzi\u0119ki nim programi\u015bci mog\u0105 z\u0142o\u017cy\u0107 wiele operacji na strumieniu w jeden \u0142a\u0144cuch, co u\u0142atwia zarz\u0105dzanie danymi w aplikacji.<\/p>\n\n\n\n<p>RxJS udost\u0119pnia nam cztery operatory wy\u017cszego rz\u0119du:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"Switchmap\">SwitchMap<\/h3>\n\n\n\n<p><strong>Operator switchMap emituje warto\u015bci wewn\u0119trznego Observable, ale ka\u017cda nowa warto\u015b\u0107 emitowana przez strumie\u0144 \u017ar\u00f3d\u0142owy powoduje anulowanie poprzedniego wewn\u0119trznego Observable i utworzenie nowego.<\/strong> Wewn\u0119trzny Observable zwr\u00f3cony z funkcji mapuj\u0105cej jest zast\u0119powany nowym wewn\u0119trznym Observable, co oznacza, \u017ce je\u015bli \u017ar\u00f3d\u0142owy strumie\u0144 emituje warto\u015bci z cz\u0119stotliwo\u015bci\u0105 wy\u017csz\u0105 ni\u017c wewn\u0119trzny Observable, operator switchMap przerywa dzia\u0142anie i zast\u0119puje poprzedni wewn\u0119trzny Observable. SwitchMap mo\u017cemy zastosowa\u0107 w przypadku, gdy chcemy odwo\u0142a\u0107 wcze\u015bniejsze \u017c\u0105dania i wys\u0142a\u0107 tylko najnowsze \u017c\u0105danie, np. dotycz\u0105ce filtrowania wynik\u00f3w wyszukiwania.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import { fromEvent } from 'rxjs'; \n\nimport { switchMap } from 'rxjs\/operators'; \n\n \n\nPobieranie danych z serwera \n\nfunction fetchData(keyword: string) { \n\n  return fetch(`https:\/\/api.github.com\/search\/repositories?q=${keyword}`).then(res => res.json()); \n\n} \n <\/pre>\n\n\n\n<p>Strumie\u0144 wej\u015bciowy z danymi z pola tekstowego<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const input$ = fromEvent(document.querySelector('input'), 'input'); <\/pre>\n\n\n\n<p>Operator switchMap ko\u0144czy subskrypcj\u0119 poprzedniego strumienia i zwraca tylko strumie\u0144 wyj\u015bciowy ostatniego wyemitowanego strumienia<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const result$ = input$.pipe( \n\n  switchMap(event => fetchData(event.target.value)) \n\n); <\/pre>\n\n\n\n<p>Subskrypcja strumienia wyj\u015bciowego<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">result$.subscribe( \n\n  data => console.log(data), \n\n  err => console.error(err), \n\n  () => console.log('Complete') \n\n); <\/pre>\n\n\n\n<p>W tym przyk\u0142adzie operator switchMap przekszta\u0142ca ka\u017cd\u0105 warto\u015b\u0107 strumienia wej\u015bciowego (event z pola tekstowego) na strumie\u0144 wyj\u015bciowy, kt\u00f3ry pobiera dane z serwera GitHub API na podstawie frazy wyszukiwania. Dzi\u0119ki temu, kiedy u\u017cytkownik wprowadza now\u0105 fraz\u0119, operator switchMap anuluje subskrypcj\u0119 poprzedniego strumienia wyj\u015bciowego i zwraca tylko wynik dla ostatniej frazy.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"Mergemap\">MergeMap<\/h3>\n\n\n\n<p>Operator mergeMap<strong> przetwarza wszystkie warto\u015bci w strumieniu \u017ar\u00f3d\u0142owym jednocze\u015bnie, emituj\u0105c warto\u015bci wewn\u0119trzne Observable<\/strong>. Operator tworzy wiele wewn\u0119trznych Observables, co oznacza, \u017ce wynikowy strumie\u0144 wyj\u015bciowy mo\u017ce emitowa\u0107 warto\u015bci w dowolnej kolejno\u015bci. Przyk\u0142adowym zastosowaniem operatora mergeMap mo\u017ce by\u0107 r\u00f3wnoleg\u0142e pobieranie danych z wielu \u017ar\u00f3de\u0142.<\/p>\n\n\n\n<p>Operator mergeMap jest szczeg\u00f3lnie przydatny w sytuacjach, gdy potrzebujemy wykona\u0107 operacj\u0119 asynchroniczn\u0105 dla ka\u017cdego elementu strumienia wej\u015bciowego i uzyska\u0107 strumie\u0144 wyj\u015bciowy sk\u0142adaj\u0105cy si\u0119 z wynik\u00f3w tych operacji.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import { from, Observable } from 'rxjs'; \n\nimport { mergeMap } from 'rxjs\/operators'; <\/pre>\n\n\n\n<p>Definicja funkcji zwracaj\u0105cej strumie\u0144 asynchroniczny<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">function makeHttpRequest(id: number): Observable {\n\nreturn fetch(https:\/\/jsonplaceholder.typicode.com\/posts\/${id}).then(res => res.json());\n\n}<\/pre>\n\n\n\n<p>Strumie\u0144 wej\u015bciowy z list\u0105 identyfikator\u00f3w<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const ids$ = from([1, 2, 3, 4, 5]); \n\n <\/pre>\n\n\n\n<p>Operator mergeMap przekszta\u0142ca ka\u017cdy element strumienia wej\u015bciowego na strumie\u0144 wyj\u015bciowy<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const posts$ = ids$.pipe( \n\n  mergeMap(id => makeHttpRequest(id)) \n\n); <\/pre>\n\n\n\n<p>Subskrypcja strumienia wyj\u015bciowego<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">posts$.subscribe( \n\n  post => console.log(post), \n\n  err => console.error(err), \n\n  () => console.log('Complete') \n\n); <\/pre>\n\n\n\n<p>W tym przyk\u0142adzie operator mergeMap przekszta\u0142ca ka\u017cdy element strumienia wej\u015bciowego (identyfikator posta) na strumie\u0144 wyj\u015bciowy reprezentuj\u0105cy wynik asynchronicznej operacji pobierania danych z serwera dla danego posta. W efekcie otrzymujemy strumie\u0144 wyj\u015bciowy sk\u0142adaj\u0105cy si\u0119 z pobranych post\u00f3w, a nie z identyfikator\u00f3w.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"Contactmap\">ContactMap<\/h3>\n\n\n\n<p>Operator concatMap emituje warto\u015bci wewn\u0119trznego Observable w kolejno\u015bci, w jakiej s\u0105 one dostarczane. Operator nie tworzy wielu wewn\u0119trznych Observables, dop\u00f3ki poprzedni Observable nie zako\u0144czy dzia\u0142ania. W przypadku, gdy w strumieniu \u017ar\u00f3d\u0142owym pojawi si\u0119 kolejna warto\u015b\u0107, zanim zako\u0144czy dzia\u0142anie poprzedni wewn\u0119trzny Observable. Operator concatMap umieszcza warto\u015bci kolejnego wewn\u0119trznego Observable w kolejce i przetwarza je dopiero po zako\u0144czeniu poprzedniego Observable.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import { of } from 'rxjs'; \n\nimport { concatMap, delay } from 'rxjs\/operators'; <\/pre>\n\n\n\n<p>Strumie\u0144 wej\u015bciowy z liczbami<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const source$ = of(1, 2, 3, 4, 5); <\/pre>\n\n\n\n<p>Operator concatMap przekszta\u0142ca ka\u017cdy element strumienia wej\u015bciowego na nowy strumie\u0144 wyj\u015bciowy z op\u00f3\u017anieniem w zale\u017cno\u015bci od warto\u015bci elementu<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const example$ = source$.pipe( \n\n  concatMap(value => of(`Delayed by: ${value * 1000}ms`).pipe(delay(value * 1000))) \n\n); <\/pre>\n\n\n\n<p>Subskrypcja strumienia wyj\u015bciowego<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">example$.subscribe(console.log); <\/pre>\n\n\n\n<p>W powy\u017cszym przyk\u0142adzie concatMap przekszta\u0142ca ka\u017cd\u0105 warto\u015b\u0107 strumienia wej\u015bciowego (1, 2, 3, 4, 5) na strumie\u0144 wyj\u015bciowy, kt\u00f3ry zostaje op\u00f3\u017aniony o warto\u015b\u0107 elementu w sekundach i zwr\u00f3cony w kolejno\u015bci ich pojawiania si\u0119 w \u017ar\u00f3d\u0142owym strumieniu. Dzi\u0119ki temu pierwszy element (1) zostanie zwr\u00f3cony po jednej sekundzie, drugi element (2) po dw\u00f3ch sekundach itd.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"exhaustmap\">ExhaustMap<\/h3>\n\n\n\n<p>Operator exhaustMap<strong> przekszta\u0142ca ka\u017cdy element strumienia wej\u015bciowego (\u017ar\u00f3d\u0142owego) na nowy strumie\u0144 i ignoruje wszystkie kolejne elementy, zanim zako\u0144czy dzia\u0142anie strumie\u0144 wyj\u015bciowy.<\/strong><\/p>\n\n\n\n<p>ExhaustMap jest przydatny, gdy jest nam potrzebne, \u017ceby w danym czasie by\u0142 emitowany tylko jeden strumie\u0144 wyj\u015bciowy. W przypadku, gdy pojawiaj\u0105 si\u0119 nowe elementy w strumieniu wej\u015bciowym przed zako\u0144czeniem strumienia wyj\u015bciowego, s\u0105 one ignorowane a\u017c do zako\u0144czenia dzia\u0142ania poprzedniego strumienia wyj\u015bciowego.<\/p>\n\n\n\n<p>Przyk\u0142adowym zastosowaniem operatora exhaustMap mo\u017ce by\u0107 ograniczenie liczby \u017c\u0105da\u0144 sieciowych w sytuacji, gdy w aplikacji u\u017cytkownik kliknie wiele razy na przycisk, ale zwr\u00f3cone zostanie tylko jedno zapytanie.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"> \n\nimport { interval } from 'rxjs'; \n\nimport { exhaustMap, take } from 'rxjs\/operators'; <\/pre>\n\n\n\n<p>Strumie\u0144 wej\u015bciowy z warto\u015bciami<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const source$ = interval(1000).pipe(take(4)); <\/pre>\n\n\n\n<p>Operator exhaustMap przekszta\u0142ca ka\u017cd\u0105 warto\u015b\u0107 strumienia wej\u015bciowego na nowy strumie\u0144 wyj\u015bciowy, kt\u00f3ry zostaje zwr\u00f3cony dopiero po zako\u0144czeniu dzia\u0142ania jego poprzednika.&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">const example$ = source$.pipe( \n\n  exhaustMap(value => interval(500).pipe(take(3))) \n\n); <\/pre>\n\n\n\n<p>Subskrypcja strumienia wyj\u015bciowego&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">example$.subscribe(console.log); <\/pre>\n\n\n\n<p>Powy\u017cszy przyk\u0142ad obrazuje sytuacje, gdy operator exhaustMap przekszta\u0142ca ka\u017cd\u0105 warto\u015b\u0107 strumienia wej\u015bciowego (0, 1, 2, 3) na strumie\u0144 wyj\u015bciowy emituj\u0105cy warto\u015bci z op\u00f3\u017anieniem 0,5 sekundy. Ka\u017cdy kolejny strumie\u0144 wyj\u015bciowy zostanie zignorowany, dop\u00f3ki poprzedni nie zostanie zako\u0144czony, dlatego drugi strumie\u0144 wyj\u015bciowy z warto\u015bciami (0, 1, 2) nie zostanie wyemitowany, poniewa\u017c pierwszy strumie\u0144 z warto\u015bciami (0, 1, 2) nadal jest w trakcie emisji.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Podsumowuj\u0105c:<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>exhaustMap<\/strong> ignoruje nowe zdarzenia, je\u015bli obecny strumie\u0144 wci\u0105\u017c trwa. Je\u015bli w trakcie trwania strumienia wej\u015bciowego operator otrzyma kolejne zdarzenie, to zostanie ono pomini\u0119te, a\u017c do momentu, gdy strumie\u0144 wej\u015bciowy si\u0119 zako\u0144czy.<\/li>\n\n\n\n<li><strong>mergeMap<\/strong> przetwarza wszystkie warto\u015bci w strumieniu \u017ar\u00f3d\u0142owym jednocze\u015bnie, emituj\u0105c warto\u015bci wewn\u0119trznych Observables.<\/li>\n\n\n\n<li><strong>concatMap<\/strong> emituje warto\u015bci wewn\u0119trznego Observable w kolejno\u015bci, w jakiej s\u0105 one emitowane.<\/li>\n\n\n\n<li><strong>switchMap<\/strong> emituje warto\u015bci wewn\u0119trznego Observable, ale zast\u0119puje poprzedni wewn\u0119trzny Observable nowym, gdy \u017ar\u00f3d\u0142owy strumie\u0144 emituje nowe warto\u015bci.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"faq\">FAQ:&nbsp;&nbsp;<\/h2>\n\n\n<div id=\"rank-math-faq\" class=\"rank-math-block\">\n<div class=\"rank-math-list \">\n<div id=\"faq-question-1682427320388\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Czym jest RxJS?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>RxJS to biblioteka programistyczna napisana w j\u0119zyku JavaScript, kt\u00f3ra implementuje wzorzec programowania reaktywnego, oparty na strumieniach danych. RxJSu <strong>umo\u017cliwia programowanie reaktywne w j\u0119zyku JavaScript<\/strong>.<\/p>\n<p>Biblioteka RxJS zapewnia programistom szereg narz\u0119dzi i operacji do tworzenia, przetwarzania i obs\u0142ugi strumieni danych. Umo\u017cliwia tworzenie i \u0142\u0105czenie strumieni z r\u00f3\u017cnych \u017ar\u00f3de\u0142, np. interakcji u\u017cytkownika czy zapyta\u0144 HTTP. RxJS dostarcza tak\u017ce wiele operator\u00f3w, kt\u00f3re umo\u017cliwiaj\u0105 transformowanie, filtrowanie i \u0142\u0105czenie strumieni danych.<\/p>\n<p>RxJS ma wiele zastosowa\u0144, takich jak obs\u0142uga zdarze\u0144 interakcji u\u017cytkownika w aplikacjach internetowych, tworzenie strumieni danych z serwera lub integracja z frameworkami frontendowymi, takimi jak Angular czy React.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-question-1682427349404\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Czym jest strumie\u0144 danych w programowaniu reaktywnym?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>W programowaniu reaktywnym strumie\u0144 danych to sekwencja zdarze\u0144, kt\u00f3ra mo\u017ce mie\u0107 miejsce w czasie i by\u0107 przetwarzana asynchronicznie. Mo\u017ce to by\u0107 na przyk\u0142ad strumie\u0144 zdarze\u0144 z interfejsu u\u017cytkownika, strumie\u0144 danych z sieci, pliku, bazy danych lub innego \u017ar\u00f3d\u0142a. <strong>Strumienie danych s\u0105 kluczowym elementem w programowaniu reaktywnym, poniewa\u017c pozwalaj\u0105 na przetwarzanie zdarze\u0144 i reagowanie na nie w czasie rzeczywistym, w miar\u0119 ich pojawiania si\u0119<\/strong>. Strumienie mog\u0105 mie\u0107 zero lub wiele warto\u015bci. W bibliotece RxJS operatorami s\u0105 funkcje, kt\u00f3re pozwalaj\u0105 na prac\u0119 z asynchronicznymi strumieniami danych. Dzi\u0119ki wykorzystaniu operator\u00f3w i strumieni danych programowanie reaktywne umo\u017cliwia tworzenie skalowalnych, elastycznych i wydajnych aplikacji. Szerzej zosta\u0142o to opisane w artykule \u201eProgramowanie reaktywne w JS z RxJS\u201d.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-question-1682427351812\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Jak efektywniej wykorzysta\u0107 bibliotek\u0119 RxJS?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>&#8211; <strong>U\u017cywaj Observables zamiast Promises <\/strong>\u2013 Observables s\u0105 bardziej elastyczne ni\u017c Promises i pozwalaj\u0105 na \u0142atwe operowanie na strumieniu danych.<br \/>&#8211; <strong>Unikaj nadmiernego korzystania z operator\u00f3w <\/strong>\u2013 operator\u00f3w w RxJS jest wiele i bardzo \u0142atwo jest przesadzi\u0107 z ich wykorzystaniem. Zawsze nale\u017cy zastanowi\u0107 si\u0119, czy dany operator jest potrzebny i czy faktycznie przyczynia si\u0119 do poprawy czytelno\u015bci i wydajno\u015bci kodu.<br \/>&#8211; <strong>Unikaj jednoczesnego korzystania z wielu strumieniu<\/strong> \u2013 w RxJS bardzo \u0142atwo jest stworzy\u0107 wiele strumieni danych, co mo\u017ce prowadzi\u0107 do problem\u00f3w z wydajno\u015bci\u0105 aplikacji. Zawsze nale\u017cy zastanowi\u0107 si\u0119, czy rzeczywi\u015bcie potrzebujemy tak wielu strumieni i czy nie da si\u0119 ich po\u0142\u0105czy\u0107 w jeden.<br \/>&#8211; <strong>Zwracaj uwag\u0119 na pami\u0119\u0107<\/strong> \u2013 w RxJS strumienie danych s\u0105 po\u0142\u0105czone z pami\u0119ci\u0105, wi\u0119c warto zwraca\u0107 uwag\u0119 na to, czy nie tworzymy niepotrzebnie du\u017cych strumieni, kt\u00f3re mog\u0105 powodowa\u0107 problemy z wydajno\u015bci\u0105.<br \/>&#8211; <strong>Korzystaj z operator\u00f3w wysokiego rz\u0119du<\/strong> \u2013 operator wysokiego rz\u0119du w RxJS pozwala na tworzenie bardziej skomplikowanych strumieni danych. Ich umiej\u0119tne wykorzystanie mo\u017ce znacznie u\u0142atwi\u0107 prac\u0119 i poprawi\u0107 czytelno\u015b\u0107 kodu.<br \/>&#8211; <strong>Testuj kod <\/strong>\u2013 RxJS jest bardzo pot\u0119\u017cn\u0105 bibliotek\u0105, ale wymaga ona r\u00f3wnie\u017c wi\u0119cej uwagi podczas testowania. Zawsze warto pami\u0119ta\u0107 o testowaniu swojego kodu.<\/p>\n<p>Powy\u017csze porady s\u0105 og\u00f3lne i zale\u017c\u0105 od konkretnych wymaga\u0144 projektu. W ka\u017cdym przypadku warto jednak pami\u0119ta\u0107 o zachowaniu czytelno\u015bci i przejrzysto\u015bci kodu, a tak\u017ce o testowaniu swojego rozwi\u0105zania.<\/p>\n\n<\/div>\n<\/div>\n<div id=\"faq-question-1682427440915\" class=\"rank-math-list-item\">\n<h3 class=\"rank-math-question \">Czym jest typ obiektu? Dlaczego musisz go zasubskrybowa\u0107, aby otrzyma\u0107 dane?<\/h3>\n<div class=\"rank-math-answer \">\n\n<p>Typ obiektu w RxJS to abstrakcyjny typ danych, kt\u00f3ry reprezentuje strumie\u0144 warto\u015bci emitowanych przez \u017ar\u00f3d\u0142o. Typ ten definiuje interfejs do tworzenia, przetwarzania i subskrybowania strumieni danych w programowaniu reaktywnym.<\/p>\n<p>Wa\u017cn\u0105 cech\u0105 strumienia danych w RxJS jest to, \u017ce <strong>nie emituje on danych do subskrybenta automatycznie<\/strong>. W przeciwie\u0144stwie do klasycznych zapyta\u0144 HTTP, kt\u00f3re zwracaj\u0105 wynik tylko raz, strumienie danych mog\u0105 emitowa\u0107 warto\u015bci wielokrotnie w czasie. Aby otrzyma\u0107 warto\u015bci emitowane przez strumie\u0144 danych, musisz zasubskrybowa\u0107 go, czyli utworzy\u0107 subskrypcj\u0119. Subskrypcja reprezentuje po\u0142\u0105czenie pomi\u0119dzy subskrybentem a \u017ar\u00f3d\u0142em danych, kt\u00f3re umo\u017cliwia odbieranie warto\u015bci emitowanych przez strumie\u0144.<\/p>\n<p>Subskrypcja umo\u017cliwia r\u00f3wnie\u017c zarz\u0105dzanie cyklem \u017cycia strumienia danych. Mo\u017cesz anulowa\u0107 subskrypcj\u0119, je\u015bli nie potrzebujesz ju\u017c otrzymywa\u0107 warto\u015bci z danego strumienia. Mo\u017cesz r\u00f3wnie\u017c wykonywa\u0107 r\u00f3\u017cne operacje na strumieniu, takie jak transformacje, filtrowanie lub \u0142\u0105czenie z innymi strumieniami, poprzez u\u017cycie operator\u00f3w RxJS.<\/p>\n<p>Podsumowuj\u0105c, <strong>subskrypcja jest niezb\u0119dna, aby otrzyma\u0107 warto\u015bci emitowane przez strumie\u0144 danych w RxJS<\/strong>. Dzi\u0119ki temu, \u017ce subskrypcje umo\u017cliwiaj\u0105 zarz\u0105dzanie cyklem \u017cycia strumienia, mo\u017cna w \u0142atwy spos\u00f3b manipulowa\u0107 przep\u0142ywem danych w programowaniu reaktywnym.<\/p>\n\n<\/div>\n<\/div>\n<\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>Biblioteka RxJs, kt\u00f3r\u0105 szczeg\u00f3\u0142owo opisa\u0142em w poprzednim artykule, oferuje szereg mo\u017cliwo\u015bci pracy z danymi, reagowania na zachowania u\u017cytkownika czy wszelkie inne zdarzenia zachodz\u0105ce w aplikacji. W skr\u00f3cie: RxJs to biblioteka u\u0142atwiaj\u0105ca wykorzystanie konceptu programowania reaktywnego. Jednym z takich u\u0142atwie\u0144 s\u0105 operatory wy\u017cszego rz\u0119du. Z tego artyku\u0142u dowiesz si\u0119, czym jest Higher-Order Observable Mapping w RxjS, jakie s\u0105 rodzaje operator\u00f3w i jak mog\u0105 ci pom\u00f3c w pracy ze strumieniowymi danymi. Zaczynajmy!<\/p>\n","protected":false},"author":110,"featured_media":29890,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"iawp_total_views":178,"footnotes":""},"categories":[1,582],"tags":[614,570],"offering":[522],"class_list":["post-29889","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-artykuly","category-technologie","tag-application-development","tag-javascript-pl","offering-tech-blog"],"acf":[],"_links":{"self":[{"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/posts\/29889","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/users\/110"}],"replies":[{"embeddable":true,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/comments?post=29889"}],"version-history":[{"count":6,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/posts\/29889\/revisions"}],"predecessor-version":[{"id":33885,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/posts\/29889\/revisions\/33885"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/media\/29890"}],"wp:attachment":[{"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/media?parent=29889"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/categories?post=29889"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/tags?post=29889"},{"taxonomy":"offering","embeddable":true,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/offering?post=29889"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}