{"id":13905,"date":"2022-06-06T07:00:35","date_gmt":"2022-06-06T05:00:35","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=13905"},"modified":"2023-07-05T16:40:09","modified_gmt":"2023-07-05T14:40:09","slug":"more-reactive-angular","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/more-reactive-angular\/","title":{"rendered":"More reactive Angular"},"content":{"rendered":"\n<p>W dzisiejszym artykule przybli\u017c\u0119 temat Reactive Extensions \u2013 skutecznego narz\u0119dzia do rozwi\u0105zywania okre\u015blonych klas problem\u00f3w, cho\u0107 niekoniecznie wszystkim dobrze znanego.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Co to jest Reactive Extensions?<\/h2>\n\n\n\n<p>Autorzy opisuj\u0105 Reactive Extensions (lub ReactiveX, Rx) jako API do programowania asynchronicznego z u\u017cyciem obserwowalnych strumieni (Observable streams). Jest ono dost\u0119pne dla kilku r\u00f3\u017cnych j\u0119zyk\u00f3w programowania m.in.:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Java,<\/li>\n\n\n\n<li>JavaScript,<\/li>\n\n\n\n<li>C#,<\/li>\n\n\n\n<li>C++,<\/li>\n\n\n\n<li>Scala,<\/li>\n\n\n\n<li>PHP,<\/li>\n\n\n\n<li>Python,<\/li>\n\n\n\n<li>Go,<\/li>\n\n\n\n<li>Dart i innych.<\/li>\n<\/ul>\n\n\n\n<p>W Angular wykorzystywana jest implementacja RxJS. Jak sama nazwa wskazuje, jest to wersja dla JavaScript.<\/p>\n\n\n\n<p>O ile programowanie reaktywne (reactive programming), mo\u017ce by\u0107 bardziej znane, to dla kogo\u015b, kto zetkn\u0105\u0142 si\u0119 z Rx po raz pierwszy, \u2018observable streams\u2019 mo\u017ce brzmie\u0107 do\u015b\u0107 tajemniczo.<\/p>\n\n\n\n<p>W\u0142a\u015bciwo\u015bci Rx sprawiaj\u0105, \u017ce s\u0105 one bardzo skuteczne do rozwi\u0105zywania okre\u015blonych klas problem\u00f3w. Jednak, zaczynaj\u0105c od pocz\u0105tku, <strong>programowanie reaktywne polega na asynchronicznym, nieblokuj\u0105cym przetwarzaniu danych i reagowaniu na zmiany w tych danych. <\/strong><\/p>\n\n\n\n<p>Gdy tylko pojawi\u0105 si\u0119 zmiany w strumieniu danych, aplikacja reaguje na te zmiany, co jest bardzo pomocne w dynamicznie zmieniaj\u0105cych si\u0119 interfejsach i aplikacjach.<\/p>\n\n\n\n<p>Strumienie w programowaniu to ci\u0105g danych przychodz\u0105cych w czasie o nieokre\u015blonej d\u0142ugo\u015bci. Strumie\u0144 mo\u017ce by\u0107 sko\u0144czony np. \u017c\u0105danie AJAX zwracaj\u0105ce jeden element lub niesko\u0144czony np. aktualna pozycja kursora.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Observable streams<\/h2>\n\n\n\n<p>Observable stream to po prostu strumie\u0144 danych ze specjalnymi w\u0142asno\u015bciami. Poza zwyk\u0142ymi elementami \u2013 danymi, kt\u00f3re mog\u0105 by\u0107 typem prymitywnym albo z\u0142o\u017conym obiektem. Observable stream mo\u017ce wysy\u0142a\u0107 dwa dodatkowe typy danych:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>b\u0142\u0105d,<\/li>\n\n\n\n<li>znacznik ko\u0144ca, gdy ju\u017c wszystkie elementy zosta\u0142y wys\u0142ane (podobie\u0144stwo do wzorca Iteratora).<\/li>\n<\/ul>\n\n\n\n<p>Taki strumie\u0144 mo\u017cna obserwowa\u0107 (subskrybowa\u0107), aby odebra\u0107 zwr\u00f3cone elementy w celu dalszego przetworzenia (wzorzec obserwatora).<\/p>\n\n\n\n<p>Reactive Extensions to po\u0142\u0105czenie zalet m.in. wzorc\u00f3w obserwatora, iteratora i programowania funkcyjnego.<\/p>\n\n\n\n<p>Observable streams s\u0105 jak funkcje w programowaniu funkcyjnym. Mog\u0105 by\u0107 argumentami dla innych strumieni (high order streams), mog\u0105 by\u0107 \u0142\u0105czone, a na elementach mog\u0105 by\u0107 przeprowadzane r\u00f3\u017cne operacje np. filtrowanie lub mapowanie. Zestaw wbudowanych operator\u00f3w jest spory, co niew\u0105tpliwie jest mocn\u0105 stron\u0105 Rx.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Dlaczego warto korzysta\u0107 z Reactive Extensions?<\/h2>\n\n\n\n<p>Rozwi\u0105zania zastosowane w Rx s\u0105 szczeg\u00f3lnie przydatne przy wielu \u017ar\u00f3d\u0142ach zdarze\u0144 i skomplikowanej logice mi\u0119dzy nimi. Implementacja obs\u0142ugi takiego strumienia jest taka sama \u2013 niezale\u017cnie, czy strumie\u0144 b\u0119dzie sk\u0142ada\u0142 si\u0119 z jednego, kilku, czy niesko\u0144czenie wielu element\u00f3w. Elementy strumienia mog\u0105 by\u0107 przetwarzane podobnie jak sko\u0144czone kolekcje np. tablice.<\/p>\n\n\n\n<p>W Angular Observable streams s\u0105 u\u017cywane do wielu asynchronicznych operacji:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>komunikacji mi\u0119dzy komponentami,<\/li>\n\n\n\n<li>zarz\u0105dzania i synchronizacji pomi\u0119dzy \u017c\u0105daniami i odpowiedziami AJAX w module http,<\/li>\n\n\n\n<li>zarz\u0105dzania routingiem i formularzami, nas\u0142uchuj\u0105c i reaguj\u0105c na zdarzenia od u\u017cytkownika.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">RxJS vs Promises<\/h2>\n\n\n\n<p>W przeciwie\u0144stwie do Promis\u00f3w Observable streams maj\u0105 nast\u0119puj\u0105ce cechy (zalety):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>pozwalaj\u0105 obs\u0142ugiwa\u0107 wi\u0119cej ni\u017c jeden event,<\/li>\n\n\n\n<li>wywo\u0142anie jest \u2018lazy\u2019 i dzieje si\u0119 w momencie subskrybowania, a nie tworzenia,<\/li>\n\n\n\n<li>mo\u017ce je anulowa\u0107\/ponawia\u0107,<\/li>\n\n\n\n<li>dostarczaj\u0105 wielu operator\u00f3w pozwalaj\u0105cych na operacje na na strumieniach i danych.<\/li>\n<\/ul>\n\n\n\n<p>Z tego wzgl\u0119du w Angular 2 zastosowano Observable streams w module Http zamiast wcze\u015bniej stosowanych Promis\u00f3w.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">W jaki spos\u00f3b to dzia\u0142a?<\/h2>\n\n\n\n<p>Przejd\u017amy do przyk\u0142adu. Dla uproszczenia nie skorzystam z formularzy w Angular.<\/p>\n\n\n\n<p>1. Punktem wyj\u015bciowym b\u0119dzie komponent, w kt\u00f3rym Rx jest u\u017cywany jedynie wewn\u0119trznie przez HttpClient. Nale\u017cy pami\u0119ta\u0107, \u017ce ka\u017cd\u0105 zdefiniowan\u0105 przez nas subskrypcj\u0119 Observable stream nale\u017cy zako\u0144czy\u0107 przy niszczeniu komponentu, aby unikn\u0105\u0107 wycieku pami\u0119ci. Nie dotyczy to strumieni z HttpClient, poniewa\u017c po otrzymaniu elementu lub b\u0142\u0119du wysy\u0142any jest znak ko\u0144ca strumienia.<\/p>\n\n\n\n<p>Komponent jest napisany w stylu imperatywnym. Ci\u0105g instrukcji zosta\u0142 krok po kroku zdefiniowany przez programist\u0119. Po zasubskrybowaniu otrzymane dane przypisujemy do zmiennej, a potem je przekszta\u0142camy.<\/p>\n\n\n\n<p>Tutaj mo\u017cesz zobaczy\u0107, jak <a href=\"https:\/\/stackblitz.com\/edit\/angular-ivy-u4uwej?file=src%2Fapp%2Fsearch-flight1.component.ts\" rel=\"nofollow\" >wygl\u0105da\u0142o moje pierwsze podej\u015bcie do Angulara, gdy nie wiedzia\u0142em nic o Rx<\/a>.<\/p>\n\n\n\n<p>2. Kolejne kroki b\u0119d\u0105 przej\u015bciem od programowania imperatywnego do programowania deklaratywnego. <a href=\"https:\/\/stackblitz.com\/edit\/angular-ivy-u4uwej?file=src%2Fapp%2Fsearch-flight2.component.ts\" rel=\"nofollow\" >W tym kroku zmieniamy podej\u015bcia do definiowania danych potrzebnych do wy\u015bwietlenia w template<\/a>. Zamiast modyfikowa\u0107 dane otrzymane z zapytania http, definiujemy Observable stream, kt\u00f3ry wykorzystuje strumie\u0144 bazowy oraz modyfikuje przychodz\u0105ce dane. W ten spos\u00f3b nie zarz\u0105dzamy ci\u0105giem instrukcji, kt\u00f3rym maj\u0105 by\u0107 poddane przychodz\u0105ce dane, a definiujemy kszta\u0142t (typ) danych, kt\u00f3re chcemy otrzyma\u0107.<\/p>\n\n\n\n<p>3. <a href=\"https:\/\/stackblitz.com\/edit\/angular-ivy-u4uwej?file=src%2Fapp%2Fsearch-flight3.component.ts\" rel=\"nofollow\" >Zdefiniowane strumienie przypisujemy do zmiennych<\/a>. Powszechn\u0105 praktyk\u0105 jest dodawanie znaku $ na ko\u0144cu nazwy zmiennej w celu oznaczenia, \u017ce jest to Observable stream.<\/p>\n\n\n\n<p>4. Kolejnym krokiem b\u0119dzie <a href=\"https:\/\/stackblitz.com\/edit\/angular-ivy-u4uwej?file=src%2Fapp%2Fsearch-flight4.component.ts\" rel=\"nofollow\" >separacja logiki odpowiedzialnej za pobieranie danych do serwisu<\/a>.<\/p>\n\n\n\n<p>5. Usuwamy zmienne z danymi i zostawiamy tylko zdefiniowane wcze\u015bniej Observable streams. Nie subskrybujemy strumieni w komponencie. U\u017cywamy strumieni w template u\u017cywaj\u0105c \u2018async\u2019 pipe. <a href=\"https:\/\/stackblitz.com\/edit\/angular-ivy-u4uwej?file=src%2Fapp%2Fsearch-flight5.component.ts\" rel=\"nofollow\" >Dzi\u0119ki temu subskrypcj\u0105 i jej zako\u0144czeniem zarz\u0105dza za nas Angular<\/a>.<\/p>\n\n\n\n<p>6. Cieszymy si\u0119 czytelnym i \u0142atwym w utrzymaniu kodem. Przyk\u0142ad nie jest skomplikowany. W miar\u0119 rosn\u0105cego skomplikowania zale\u017cno\u015bci pomi\u0119dzy danymi, elementami interfejsu i akcjami u\u017cytkownika, korzy\u015bci p\u0142yn\u0105ce z u\u017cywania Rx s\u0105 coraz bardziej widoczne.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Podsumowanie<\/h2>\n\n\n\n<p>Koncepcja reactive programming oraz implementacja Reactive Extensions nie jest \u015bci\u015ble zwi\u0105zana z Angular ani \u017cadnym konkretnym j\u0119zykiem programowania. Jest to rozwi\u0105zanie pewnej klasy problem\u00f3w, kt\u00f3re pojawiaj\u0105 si\u0119 zar\u00f3wno w aplikacjach frontendowych jak i backendowych, niezale\u017cnie od stosowanej technologii. Z powodzeniem mo\u017cna u\u017cywa\u0107 RxJS z VanillaJS.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Wi\u0119cej o Reactive Extensions dowiesz si\u0119 z:<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/reactivex.io\/\" rel=\"nofollow\" >Reactivex.io<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/angular.io\/guide\/observables-in-angular\" rel=\"nofollow\" >Angular.io<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.learnrxjs.io\/\" rel=\"nofollow\" >Learnrxjs.io<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/gist.github.com\/staltz\/868e7e9bc2a7b8c1f754\" rel=\"nofollow\" >Introduction to Reactive Programming<\/a><\/li>\n<\/ul>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;13905&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;4&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( votes: 4)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;More reactive Angular&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( votes: 4)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>W dzisiejszym artykule przybli\u017c\u0119 temat Reactive Extensions \u2013 skutecznego narz\u0119dzia do rozwi\u0105zywania okre\u015blonych klas problem\u00f3w, cho\u0107 niekoniecznie wszystkim dobrze znanego. &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/more-reactive-angular\/\">Continued<\/a><\/p>\n","protected":false},"author":368,"featured_media":14781,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1316],"tags":[287,129,1026,1279,1278],"class_list":["post-13905","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-miekko","tag-software-development","tag-c","tag-api","tag-observable-streams","tag-reactive-extensions"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2022\/06\/More-reactive-angular-1.png","category_names":["Development na mi\u0119kko"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/13905"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/368"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=13905"}],"version-history":[{"count":2,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/13905\/revisions"}],"predecessor-version":[{"id":22682,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/13905\/revisions\/22682"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/14781"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=13905"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=13905"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=13905"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}