{"id":36774,"date":"2019-10-31T22:13:44","date_gmt":"2019-10-31T19:13:44","guid":{"rendered":"https:\/\/prohoster.info\/blog\/asinhronnoe-programmirovanie-v-javascript-callback-promise-rxjs\/"},"modified":"2019-10-31T22:13:44","modified_gmt":"2019-10-31T19:13:44","slug":"asinhronnoe-programmirovanie-v-javascript-callback-promise-rxjs","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pl\/blog\/news\/asinhronnoe-programmirovanie-v-javascript-callback-promise-rxjs","title":{"rendered":"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Cze\u015b\u0107 wszystkim. Z tej strony Omyelnitsky Sergey. Niedawno prowadzi\u0142em strumie\u0144 na temat programowania reaktywnego, gdzie opowiada\u0142em o asynchroniczno\u015bci w JavaScript. Dzi\u015b chcia\u0142bym podsumowa\u0107 ten materia\u0142. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/11acf6af8328d3deb6f0ce48e813efb7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ale zanim zaczniemy od g\u0142\u00f3wnego materia\u0142u, musimy zrobi\u0107 wprowadzenie. Zacznijmy od definicji: co to jest stos i kolejka?<br \/>\n<strong>Stos <\/strong>to zbi\u00f3r, w kt\u00f3rym elementy s\u0105 pobierane wed\u0142ug zasady \u201eostatni wszed\u0142, pierwszy wyszed\u0142\u201d LIFO.<br \/>\n<strong>Kolejka <\/strong>to zbi\u00f3r, w kt\u00f3rym elementy s\u0105 pobierane wed\u0142ug zasady \u201epierwszy wszed\u0142, pierwszy wyszed\u0142\u201d FIFO.<\/p>\n<p><\/p>\n<p>Dobrze, kontynuujmy. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/a7d64d1c74f37b463869dd57b96c9d0e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>JavaScript to j\u0119zyk programowania jednow\u0105tkowego. Oznacza to, \u017ce ma tylko jeden w\u0105tek wykonawczy i jeden stos, do kt\u00f3rego funkcje s\u0105 dodawane w kolejce do wykonania. W zwi\u0105zku z tym w danym momencie JavaScript mo\u017ce wykona\u0107 tylko jedn\u0105 operacj\u0119, a pozosta\u0142e operacje b\u0119d\u0105 czeka\u0107 w kolejce na stosie, a\u017c zostan\u0105 wywo\u0142ane. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p><strong>Stos wywo\u0142a\u0144<\/strong> to struktura danych, kt\u00f3ra, m\u00f3wi\u0105c uproszczonym j\u0119zykiem, zapisuje informacje o miejscu w programie, w kt\u00f3rym si\u0119 znajdujemy. Gdy przechodzimy do funkcji, dodajemy wpis o niej do g\u00f3rnej cz\u0119\u015bci stosu. Kiedy wracamy z funkcji, usuwamy z g\u00f3ry stosu najnowszy element i wracamy tam, sk\u0105d wywo\u0142ano t\u0119 funkcj\u0119. To wszystko, czym dysponuje stos. A teraz bardzo interesuj\u0105ce pytanie: jak zatem dzia\u0142a asynchroniczno\u015b\u0107 w JavaScript?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/a29fd1dd3de06fb203c7dd14bda30548.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>W rzeczywisto\u015bci opr\u00f3cz stosu w przegl\u0105darkach istnieje specjalna kolejka do pracy z tzw. WebAPI. Funkcje w tej kolejce zostan\u0105 wykonane w porz\u0105dku tylko po ca\u0142kowitym opr\u00f3\u017cnieniu stosu. Dopiero wtedy zostan\u0105 przeniesione z kolejki do stosu do wykonania. Je\u015bli w stosie jest przynajmniej jeden element, nie mog\u0105 one wej\u015b\u0107 na stos. To w\u0142a\u015bnie z tego powodu wywo\u0142ania funkcji po up\u0142ywie czasu cz\u0119sto s\u0105 nieterminowe, poniewa\u017c funkcja nie mo\u017ce wej\u015b\u0107 z kolejki do stosu, dop\u00f3ki jest on zaj\u0119ty. <\/p>\n<p><\/p>\n<p>Przyjrzyjmy si\u0119 nast\u0119puj\u0105cemu przyk\u0142adowi i zajmijmy si\u0119 jego krokowym \u201ewykonaniem\u201d. Zobaczmy r\u00f3wnie\u017c, co w tym czasie dzieje si\u0119 w systemie.<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">console.log('Hi);\nsetTimeout(function cb1() {\n    console.log('cb1');\n}, 5000);\nconsole.log('Bye');<\/code><\/pre>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/379423fca95fb28b2124be03dfd15739.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>1) Na razie nic si\u0119 nie dzieje. Konsola przegl\u0105darki jest czysta, stos wywo\u0142a\u0144 pusty.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/4a16bbc23bade54ae0b02d81d5f6a581.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>2) Nast\u0119pnie polecenie console.log(\u2018Hi\u2019) zostaje dodane do stosu wywo\u0142a\u0144.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/a1845af23fd7dedebf94afc168f1f13f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>3) I jest wykonywane.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/57397b53386018b662f3a79a6d4d60fb.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>4) Potem console.log(\u2018Hi\u2019) zostaje usuni\u0119te ze stosu wywo\u0142a\u0144.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/7cb2b32be8807ecf39d2f38683ccd435.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>5) Teraz przechodzimy do polecenia setTimeout(function cb1() {\u2026 }). Zostaje dodane do stosu wywo\u0142a\u0144.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/99c0724994e3390d009577852b451beb.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>6) Polecenie setTimeout(function cb1() {\u2026 }) jest wykonywane. Przegl\u0105darka tworzy licznik, kt\u00f3ry jest cz\u0119\u015bci\u0105 Web API. Rozpocznie odliczanie czasu.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/99086cdeafd83c5fe72e92c4a9f9b738.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>7) Polecenie setTimeout(function cb1() {\u2026 }) zako\u0144czy\u0142o dzia\u0142anie i zosta\u0142o usuni\u0119te ze stosu wywo\u0142a\u0144.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/24ac12b1b6cfbff780ece9e9a7acd7c7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>8) Polecenie console.log(\u2018Bye\u2019) zostaje dodane do stosu wywo\u0142a\u0144.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/6ccad0ad8eebf05e870a409766d38766.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>9) Polecenie console.log(\u2018Bye\u2019) zostaje wykonane.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/09e4e380eb873fb23bea550f3ffb21f7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>10) Polecenie console.log(\u2018Bye\u2019) zostaje usuni\u0119te ze stosu wywo\u0142a\u0144.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/357bfb372361310681ba7bb1860d90d7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>11) Po up\u0142ywie co najmniej 5000 ms, licznik ko\u0144czy dzia\u0142anie i umieszcza callback cb1 w kolejce callback\u00f3w.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/8170e8ff5d3d0c56c0091658370c25cc.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>12) P\u0119tla wydarze\u0144 bierze funkcj\u0119 cb1 z kolejki callback\u00f3w i umieszcza j\u0105 w stosie wywo\u0142a\u0144.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/d858a54e82bc32d84f854610db462bc1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>13) Funkcja cb1 jest wykonywana i dodaje console.log(\u2018cb1\u2019) do stosu wywo\u0142a\u0144.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/6ca8e016389904eec57035e64d57a157.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>14) Polecenie console.log(\u2018cb1\u2019) zostaje wykonane.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/0caa645a90ac1fca5fb8a76569494d48.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>15) Polecenie console.log(\u2018cb1\u2019) zostaje usuni\u0119te ze stosu wywo\u0142a\u0144.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/aeb838fe8df3f6e3f8603a4207a6e193.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>16) Funkcja cb1 jest usuwana ze stosu wywo\u0142a\u0144.<\/p>\n<p><\/p>\n<p>Sp\u00f3jrzmy na przyk\u0142ad w dynamicznej formie:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/3836d9df513afee374f498720990e39f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Oto my, om\u00f3wili\u015bmy, jak w JavaScript zrealizowano asynchroniczno\u015b\u0107. Teraz porozmawiajmy kr\u00f3tko o ewolucji kodu asynchronicznego.<\/p>\n<p><\/p>\n<h2 id=\"evolyuciya-asinhronnogo-koda\">Ewolucja kodu asynchronicznego.<\/h2>\n<p><\/p>\n<pre><code class=\"javascript\">a(function (resultsFromA) {\n    b(resultsFromA, function (resultsFromB) {\n        c(resultsFromB, function (resultsFromC) {\n            d(resultsFromC, function (resultsFromD) {\n                e(resultsFromD, function (resultsFromE) {\n                    f(resultsFromE, function (resultsFromF) {\n                        console.log(resultsFromF);\n                    })\n                })\n            })\n        })\n    })\n});<\/code><\/pre>\n<p><\/p>\n<p>Asynchroniczne programowanie, jakie znamy w JavaScript, mo\u017cna zrealizowa\u0107 tylko za pomoc\u0105 funkcji. Mog\u0105 by\u0107 przekazywane jak ka\u017cda inna zmienna do innych funkcji. Tak narodzi\u0142y si\u0119 callbacki. I to jest fajne, zabawne i ekscytuj\u0105ce, dop\u00f3ki nie zamienia si\u0119 w smutek i t\u0119sknot\u0119. Dlaczego? Bo to proste:<\/p>\n<p><\/p>\n<ul>\n<li>Wraz ze wzrostem z\u0142o\u017cono\u015bci kodu, projekt szybko przekszta\u0142ca si\u0119 w trudne do zrozumienia wielokrotnie zagnie\u017cd\u017cone bloki \u2014 \u201ecallback hell\u201d.<\/li>\n<li>\u0141atwo mo\u017cna przeoczy\u0107 obs\u0142ug\u0119 b\u0142\u0119d\u00f3w.<\/li>\n<li>Nie mo\u017cna zwraca\u0107 wyra\u017ce\u0144 za pomoc\u0105 return.<\/li>\n<\/ul>\n<p><\/p>\n<p>Po pojawieniu si\u0119 Promise sytuacja sta\u0142a si\u0119 nieco lepsza.<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">new Promise(function(resolve, reject) {\n    setTimeout(() =&gt; resolve(1), 2000);\n\n}).then((result) =&gt; {\n    alert(result);\n    return result + 2;\n\n}).then((result) =&gt; {\n    throw new Error('FAILED HERE');\n    alert(result);\n    return result + 2;\n\n}).then((result) =&gt; {\n    alert(result);\n    return result + 2;\n\n}).catch((e) =&gt; {\n    console.log('error: ', e);\n});<\/code><\/pre>\n<p><\/p>\n<ul>\n<li>Pojawi\u0142y si\u0119 \u0142a\u0144cuchy obietnic, co poprawi\u0142o czytelno\u015b\u0107 kodu.<\/li>\n<li>Pojawi\u0142a si\u0119 oddzielna metoda przechwytywania b\u0142\u0119d\u00f3w.<\/li>\n<li>Pojawi\u0142a si\u0119 mo\u017cliwo\u015b\u0107 r\u00f3wnoleg\u0142ego wykonywania za pomoc\u0105 Promise.all.<\/li>\n<li>Zagnie\u017cd\u017con\u0105 asynchroniczno\u015b\u0107 mo\u017cemy rozwi\u0105za\u0107 za pomoc\u0105 async\/await.<\/li>\n<\/ul>\n<p><\/p>\n<p>Jednak obietnica ma swoje ograniczenia. Na przyk\u0142ad, obietnicy, bez ta\u0144ca z b\u0119bnem, nie mo\u017cna anulowa\u0107, a co najwa\u017cniejsze \u2014 dzia\u0142a z jedn\u0105 warto\u015bci\u0105.<\/p>\n<p><\/p>\n<p>No i p\u0142ynnie przeszli\u015bmy do programowania reaktywnego. Zm\u0119czony? C\u00f3\u017c, mo\u017cna zrobi\u0107 sobie herbat\u0119, przemy\u015ble\u0107 to i wr\u00f3ci\u0107 do czytania. A ja kontynuuj\u0119.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/48409ec625d57fec171214c1de332c85.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Programowanie reaktywne<\/strong>\u2014 to paradygma programowania skoncentrowana na strumieniach danych i propagacji zmian. Przyjrzyjmy si\u0119 bardziej szczeg\u00f3\u0142owo, czym jest strumie\u0144 danych.<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">\/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\nconst input = ducument.querySelector('input');\n\nconst eventsArray = [];\n\n\/\/ \u041f\u0443\u0448\u0438\u043c \u043a\u0430\u0436\u0434\u043e\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 eventsArray\ninput.addEventListener('keyup',\n    event =&gt; eventsArray.push(event)\n);<\/code><\/pre>\n<p><\/p>\n<p>Wyobra\u017amy sobie, \u017ce mamy pole wej\u015bciowe. Tworzymy tablic\u0119 i na ka\u017cde zdarzenie keyup w input b\u0119dziemy zapisywa\u0107 to zdarzenie w naszej tablicy. Przy tym chcia\u0142bym zaznaczy\u0107, \u017ce nasza tablica jest posortowana wed\u0142ug czasu, tzn. indeks p\u00f3\u017aniejszych zdarze\u0144 jest wi\u0119kszy od indeksu wcze\u015bniejszych. Taka tablica jest uproszczon\u0105 wersj\u0105 strumienia danych, ale to jeszcze nie strumie\u0144. Aby t\u0119 tablic\u0119 mo\u017cna by\u0142o nazwali strumieniem, musi ona w jaki\u015b spos\u00f3b informowa\u0107 subskrybent\u00f3w o tym, \u017ce nadesz\u0142y nowe dane. W ten spos\u00f3b dotarli\u015bmy do definicji strumienia.<\/p>\n<p><\/p>\n<h3 id=\"potok-dannyh\">Strumie\u0144 danych<\/h3>\n<p><\/p>\n<pre><code class=\"javascript\">const { interval1 } = Rx;\nconst { take } = RxOperators;\n\ninterval(1000).pipe(\n    take(4)\n)<\/code><\/pre>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/68ec447abafb6b8a323b429ed94f8252.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Strumie\u0144<\/strong>\u2014 to posortowana wed\u0142ug czasu tablica danych, kt\u00f3ra mo\u017ce informowa\u0107 o tym, \u017ce dane si\u0119 zmieni\u0142y. A teraz wyobra\u017a sobie, jak wygodnie b\u0119dzie pisa\u0107 kod, w kt\u00f3rym jedno dzia\u0142anie wymaga wywo\u0142ania kilku zdarze\u0144 w r\u00f3\u017cnych miejscach kodu. Po prostu subskrybujemy strumie\u0144 i on sam nas informuje, kiedy nast\u0105pi\u0105 zmiany. I to potrafi robi\u0107 biblioteka RxJs.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/dcb1cfca8b4d8a887b63c302a7d6c06a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>RxJS <\/strong> \u2014 to biblioteka do pracy z asynchronicznymi i zdarzeniowymi programami z u\u017cyciem obserwowalnych sekwencji. Biblioteka dostarcza podstawowy typ <em>Observable<\/em>, kilka typ\u00f3w pomocniczych (<em>Observer, Schedulers, Subjects<\/em>) oraz operatory do pracy ze zdarzeniami jako kolekcjami (<em>map, filter, reduce, every<\/em> i podobne z JavaScript Array).<\/p>\n<p><\/p>\n<p>Przyjrzyjmy si\u0119 podstawowym poj\u0119ciom tej biblioteki.<\/p>\n<p><\/p>\n<h3 id=\"observable-observer-producer\">Observable, Observer, Producer<\/h3>\n<p><\/p>\n<p>Observable \u2014 pierwszy podstawowy typ, kt\u00f3ry om\u00f3wimy. Ta klasa zawiera g\u0142\u00f3wn\u0105 cz\u0119\u015b\u0107 implementacji RxJs. Jest powi\u0105zana z obserwowalnym strumieniem, na kt\u00f3ry mo\u017cna subskrybowa\u0107 za pomoc\u0105 metody subscribe.<\/p>\n<p><\/p>\n<p>W Observable wprowadzany jest pomocniczy mechanizm do tworzenia aktualizacji, zwany <em>Observer<\/em>. \u0179r\u00f3d\u0142em warto\u015bci dla Observera jest <em>Producent<\/em>. Mo\u017ce to by\u0107 tablica, iterator, websocket, jakie\u015b zdarzenie itp. Mo\u017cna wi\u0119c powiedzie\u0107, \u017ce observable jest przewodnikiem mi\u0119dzy Producerem a Observerem. <\/p>\n<p><\/p>\n<p>Observable obs\u0142uguje trzy rodzaje zdarze\u0144 Observera:<\/p>\n<p><\/p>\n<ul>\n<li>next \u2013 nowe dane<\/li>\n<li>error \u2013 b\u0142\u0105d, je\u015bli sekwencja zako\u0144czy\u0142a si\u0119 z powodu wyj\u0105tku. To zdarzenie r\u00f3wnie\u017c sugeruje zako\u0144czenie sekwencji.<\/li>\n<li>complete \u2014 sygna\u0142 o zako\u0144czeniu sekwencji. Oznacza to, \u017ce nie b\u0119dzie ju\u017c nowych danych<\/li>\n<\/ul>\n<p><\/p>\n<p>Zobaczmy demo:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/c5bcd2af0f18b6de3ab0dbc20db595d1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Na pocz\u0105tku przetworzymy warto\u015bci 1, 2, 3, a po 1 sek. otrzymamy 4 i zako\u0144czymy nasz strumie\u0144.<\/p>\n<p>\n<b class=\"spoiler_title\">My\u015bli na g\u0142os<\/b><\/p>\n<p>I w tym momencie zrozumia\u0142em, \u017ce bardziej interesuj\u0105ce jest opowiadanie o tym ni\u017c pisanie. \ud83d\ude00 <\/p>\n<p><\/p>\n<h3 id=\"subscription\">Subscription<\/h3>\n<p><\/p>\n<p>Kiedy subskrybujemy strumie\u0144, tworzymy now\u0105 klas\u0119 <strong>subscription<\/strong>, kt\u00f3ra daje nam mo\u017cliwo\u015b\u0107 anulowania subskrypcji za pomoc\u0105 metody <em>unsubscribe<\/em>. Mo\u017cemy r\u00f3wnie\u017c grupowa\u0107 subskrypcje za pomoc\u0105 metody <em>add<\/em>. Oczywi\u015bcie mo\u017cemy r\u00f3wnie\u017c rozgrupowa\u0107 strumienie za pomoc\u0105 <em>usu\u0144<\/em>. Metody add i remove przyjmuj\u0105 inn\u0105 subskrypcj\u0119 jako argument. Nale\u017cy zauwa\u017cy\u0107, \u017ce kiedy si\u0119 wypisujemy, wypisujemy si\u0119 ze wszystkich subskrypcji podrz\u0119dnych, jakby\u015bmy wywo\u0142ywali metod\u0119 unsubscribe na nich. Przechodzimy dalej.<\/p>\n<p><\/p>\n<h3 id=\"vidy-potokov\">Rodzaje strumieni<\/h3>\n<p><\/p>\n<table>\n<thead>\n<tr>\n<th>HOT<\/th>\n<th>COLD<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Producent jest tworzony na zewn\u0105trz observable<\/td>\n<td>Producent jest tworzony wewn\u0105trz observable<\/td>\n<\/tr>\n<tr>\n<td>Dane s\u0105 przekazywane w momencie tworzenia observable<\/td>\n<td>Dane s\u0105 przekazywane w momencie subskrypcji<\/td>\n<\/tr>\n<tr>\n<td>Wymagana jest dodatkowa logika do wypisania si\u0119<\/td>\n<td>Strumie\u0144 ko\u0144czy si\u0119 samodzielnie<\/td>\n<\/tr>\n<tr>\n<td>U\u017cywa relacji jeden-do-wielu<\/td>\n<td>U\u017cywa relacji jeden-do-jednego<\/td>\n<\/tr>\n<tr>\n<td>Wszystkie subskrypcje maj\u0105 t\u0119 sam\u0105 warto\u015b\u0107<\/td>\n<td>Subskrypcje s\u0105 niezale\u017cne<\/td>\n<\/tr>\n<tr>\n<td>Dane mog\u0105 zosta\u0107 utracone, je\u015bli nie ma subskrypcji<\/td>\n<td>Wydaje wszystkie warto\u015bci strumienia dla nowej subskrypcji<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><\/p>\n<p>Gdybym mia\u0142 to przyr\u00f3wna\u0107, wyobrazi\u0142bym sobie gor\u0105cy strumie\u0144 jako film w kinie. W kt\u00f3rym momencie przyszed\u0142e\u015b, od tego momentu zacz\u0105\u0142e\u015b ogl\u0105danie. Zimny strumie\u0144 por\u00f3wna\u0142bym do telefonu do wsparcia technicznego. Ka\u017cdy, kto dzwoni, s\u0142ucha nagrania automatycznej sekretarki od pocz\u0105tku do ko\u0144ca, ale mo\u017cesz roz\u0142\u0105czy\u0107 si\u0119 za pomoc\u0105 unsubscribe.<\/p>\n<p><\/p>\n<p>Chcia\u0142bym zauwa\u017cy\u0107, \u017ce istniej\u0105 tak\u017ce tak zwane ciep\u0142e strumienie (takie okre\u015blenie spotka\u0142em bardzo rzadko, tylko w zagranicznych spo\u0142eczno\u015bciach) \u2014 to strumie\u0144, kt\u00f3ry przekszta\u0142ca si\u0119 z zimnego strumienia w gor\u0105cy. Powstaje pytanie \u2014 gdzie go u\u017cywa\u0107)) Podam przyk\u0142ad z praktyki.<\/p>\n<p><\/p>\n<p>Pracuj\u0119 z angularem. Aktywnie wykorzystuje rxjs. Aby uzyska\u0107 dane z serwera, oczekuj\u0119 zimnego strumienia i korzystam z niego w szablonie za pomoc\u0105 asyncPipe. Je\u015bli u\u017cywam tego pipera kilka razy, wracaj\u0105c do definicji zimnego strumienia, ka\u017cdy pipe b\u0119dzie pyta\u0142 dane z serwera, co delikatnie m\u00f3wi\u0105c jest dziwne. A je\u015bli przekszta\u0142c\u0119 zimny strumie\u0144 w ciep\u0142y, to zapytanie odb\u0119dzie si\u0119 tylko raz.<\/p>\n<p><\/p>\n<p>W og\u00f3le zrozumienie rodzaj\u00f3w strumieni jest do\u015b\u0107 skomplikowane dla pocz\u0105tkuj\u0105cych, ale istotne. <\/p>\n<p><\/p>\n<h3 id=\"operators\">Operatory<\/h3>\n<p><\/p>\n<pre><code class=\"javascript\">return this.http.get(`${environment.apiUrl}\/${this.apiUrl}\/trade_companies`)\n    .pipe(\n        tap(({ data }: TradeCompanyList) =&gt; this.companies$$.next(cloneDeep(data))),\n        map(({ data }: TradeCompanyList) =&gt; data)\n    );<\/code><\/pre>\n<p><\/p>\n<p>Mo\u017cliwo\u015bci pracy ze strumieniami rozszerzaj\u0105 nam operatory. Pomagaj\u0105 one kontrolowa\u0107 zdarzenia zachodz\u0105ce w Observable. Om\u00f3wimy kilka najpopularniejszych, a dok\u0142adniej z operatorami mo\u017cna zapozna\u0107 si\u0119 w linkach w przydatnych informacjach.<\/p>\n<p><\/p>\n<p><strong>Operatory \u2014 of<\/strong><\/p>\n<p><\/p>\n<p>Zaczniemy od pomocniczego operatora of. Tworzy on Observable na podstawie prostych warto\u015bci.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/68f382447e306392b025867a9a1e88e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Operatory \u2014 filter<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/24ac65fdb5ccc7f6301b3dfe49f1e804.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Operator filtrowania filter, jak mo\u017cna si\u0119 domy\u015bli\u0107 po nazwie, filtruje sygna\u0142 strumienia. Je\u015bli operator zwraca prawd\u0119, to przepuszcza dalej.<\/p>\n<p><\/p>\n<p><strong>Operatory \u2014 take<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/b3e7a2a2e03038d6fc250247ff4496a2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>take \u2014 Przyjmuje warto\u015b\u0107 liczby emit\u00f3w, po kt\u00f3rej ko\u0144czy strumie\u0144.<\/p>\n<p><\/p>\n<p><strong>Operatory \u2014 debounceTime<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/add686e546a0b6169c38fb3b457da928.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>debounceTime \u2014 odrzuca emitowane warto\u015bci, kt\u00f3re mieszcz\u0105 si\u0119 w okre\u015blonym przedziale czasowym mi\u0119dzy wyj\u015bciowymi danymi \u2014 po up\u0142ywie interwa\u0142u czasowego emituje ostatni\u0105 warto\u015b\u0107.<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">const { Observable } = Rx;\nconst { debounceTime, take } = RxOperators;\n\nObservable.create((observer) =&gt; {\n  let i = 1;\n  observer.next(i++);\n  \/\/ Emituj warto\u015b\u0107 co 1000ms\n  setInterval(() =&gt; {\n    observer.next(i++)\n  }, 1000);\n\n \/\/ Emituj warto\u015b\u0107 co 1500ms\n  setInterval(() =&gt; {\n    observer.next(i++)\n  }, 1500);\n}).pipe(\n  debounceTime(700),  \/\/ Czekaj 700ms na warto\u015b\u0107 przed przetworzeniem\n  take(3)\n);  <\/code><\/pre>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/dbb690d6fea6c43c1f0a2bdabea57934.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Operatory \u2014 takeWhile<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/120d9fe6ddf5a60ddffc8742989b27ff.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Emituje warto\u015bci, dop\u00f3ki takeWhile nie zwr\u00f3ci false, po czym wypisuje si\u0119 z strumienia.<\/p>\n<p><\/p>\n<pre><code class=\"javascript\">const { Observable } = Rx;\nconst { debounceTime, takeWhile } = RxOperators;\n\nObservable.create((observer) =&gt; {\n  let i = 1;\n  observer.next(i++);\n  \/\/ Emit value every 1000ms\n  setInterval(() =&gt; {\n    observer.next(i++)\n  }, 1000);\n}).pipe(\n  takeWhile(producer =&gt; producer &lt; 5)\n);  <\/code><\/pre>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/d2910d1bf9fab228acc9241fdbad3d4a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Operatory \u2014 combineLatest<\/strong><\/p>\n<p><\/p>\n<p>Operatory \u0142\u0105cz\u0105ce combineLatest dzia\u0142aj\u0105 podobnie do promise.all. \u0141\u0105cz\u0105 wiele strumieni w jeden. Po tym, jak ka\u017cdy strumie\u0144 emituje przynajmniej jeden wynik, otrzymujemy ostatnie warto\u015bci z ka\u017cdego w postaci tablicy. Nast\u0119pnie, po dowolnym emisji z po\u0142\u0105czonych strumieni, b\u0119d\u0105 one zwraca\u0107 nowe warto\u015bci.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/c39bc0a8a736ed30ad147055110bbf55.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<pre><code class=\"javascript\">const { combineLatest, Observable } = Rx;\nconst { take } = RxOperators;\n\nconst observer_1 = Observable.create((observer) =&gt; {\n  let i = 1;\n  \/\/ Emit value every 1000ms\n  setInterval(() =&gt; {\n    observer.next('a: ' + i++);\n  }, 1000);\n});\n\nconst observer_2 = Observable.create((observer) =&gt; {\n  let i = 1;\n  \/\/ Emit value every 750ms\n  setInterval(() =&gt; {\n    observer.next('b: ' + i++);\n  }, 750);\n});\n\ncombineLatest(observer_1, observer_2).pipe(take(5));<\/code><\/pre>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/7fc35461f446987ef81302ff7c2ed5a8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Operatory \u2014 zip<\/strong><\/p>\n<p><\/p>\n<p>Zip \u2014 czeka na warto\u015b\u0107 z ka\u017cdego strumienia i tworzy tablic\u0119 na podstawie tych warto\u015bci. Je\u015bli warto\u015b\u0107 nie przyjdzie z jakiegokolwiek strumienia, grupa nie zostanie utworzona.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/0be5ee0d2ec56bd2bc245b15d43d4cc1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<pre><code class=\"javascript\">const { zip, Observable } = Rx;\nconst { take } = RxOperators;\n\nconst observer_1 = Observable.create((observer) =&gt; {\n  let i = 1;\n  \/\/ Emit value every 1000ms\n  setInterval(() =&gt; {\n    observer.next('a: ' + i++);\n  }, 1000);\n});\n\nconst observer_2 = Observable.create((observer) =&gt; {\n  let i = 1;\n  \/\/ Emit value every 750ms\n  setInterval(() =&gt; {\n    observer.next('b: ' + i++);\n  }, 750);\n});\n\nconst observer_3 = Observable.create((observer) =&gt; {\n  let i = 1;\n  \/\/ Emit value every 500ms\n  setInterval(() =&gt; {\n    observer.next('c: ' + i++);\n  }, 500);\n});\n\nzip(observer_1, observer_2, observer_3).pipe(take(5));<\/code><\/pre>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/e2606bf8ea5f8a660699ebe896a27d80.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Operatory \u2014 forkJoin<\/strong><\/p>\n<p><\/p>\n<p>forkJoin r\u00f3wnie\u017c \u0142\u0105czy strumienie, ale emituje warto\u015b\u0107 tylko wtedy, gdy wszystkie strumienie zostan\u0105 zako\u0144czone (complete).<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/6c430d7eeafbc8a7c1c228ddfe0e44b5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<pre><code class=\"javascript\">const { forkJoin, Observable } = Rx;\nconst { take } = RxOperators;\n\nconst observer_1 = Observable.create((observer) =&gt; {\n  let i = 1;\n  \/\/ Emit value every 1000ms\n  setInterval(() =&gt; {\n    observer.next('a: ' + i++);\n  }, 1000);\n}).pipe(take(3));\n\nconst observer_2 = Observable.create((observer) =&gt; {\n  let i = 1;\n  \/\/ Emit value every 750\n  setInterval(() =&gt; {\n    observer.next('b: ' + i++);\n  }, 750);\n}).pipe(take(5));\n\nconst observer_3 = Observable.create((observer) =&gt; {\n  let i = 1;\n  \/\/ Emit value every 500\n  setInterval(() =&gt; {\n    observer.next('c: ' + i++);\n  }, 500);\n}).pipe(take(4));\n\nforkJoin(observer_1, observer_2, observer_3);<\/code><\/pre>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/df110efc7ece46fc1d8da2d7693f75bb.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Operatory \u2014 map<\/strong><\/p>\n<p><\/p>\n<p>Operator transformacji map przekszta\u0142ca warto\u015b\u0107 emisji w now\u0105. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/2196ff9f82dd7aaeb00ab76475176d32.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<pre><code class=\"javascript\">const { Observable } = Rx;\nconst { take, map } = RxOperators;\n\nObservable.create((observer) =&gt; {\n  let i = 1;\n  \/\/ Emit value every 1000ms\n  setInterval(() =&gt; {\n    observer.next(i++);\n  }, 1000);\n}).pipe(\n  map(x =&gt; x * 10),\n  take(3)\n);\n<\/code><\/pre>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/4e4ff3e2eb4acf69f16559c711a2e666.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Operatory \u2013 share, tap<\/strong><\/p>\n<p><\/p>\n<p>Operator tap \u2014 pozwala na wykonywanie efekt\u00f3w ubocznych, czyli dzia\u0142a\u0144, kt\u00f3re nie wp\u0142ywaj\u0105 na sekwencj\u0119.<\/p>\n<p><\/p>\n<p>Operator pomocniczy share potrafi przekszta\u0142ci\u0107 zimny strumie\u0144 w gor\u0105cy. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Programowanie asynchroniczne w JavaScript. ( Callback, Promise, RxJs )\" src=\"\/wp-content\/uploads\/2019\/08\/c46e96420ed78d197ceef829ff74c82d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Sko\u0144czyli\u015bmy z operatorami. Przejd\u017amy do Subject.<\/p>\n<p>\n<b class=\"spoiler_title\">My\u015bli na g\u0142os<\/b><\/p>\n<p>I wtedy poszed\u0142em na herbat\u0119. Te przyk\u0142ady mnie zm\u0119czy\u0142y \ud83d\ude00<\/p>\n<p><\/p>\n<h2 id=\"semeystvo-subject-ov\">Rodzina subject\u00f3w<\/h2>\n<p><\/p>\n<p>Rodzina subject\u00f3w jest wyra\u017anym przyk\u0142adem gor\u0105cych strumieni. Te klasy s\u0105 pewnym hybryd\u0105, kt\u00f3re pe\u0142ni\u0105 jednocze\u015bnie rol\u0119 observable i observer. Poniewa\u017c subject jest gor\u0105cym strumieniem, nale\u017cy z niego wypisywa\u0107. Je\u015bli m\u00f3wimy o g\u0142\u00f3wnych metodach, to s\u0105 to:<\/p>\n<p><\/p>\n<ul>\n<li>next \u2013 przesy\u0142anie nowych danych do strumienia<\/li>\n<li>error \u2013 b\u0142\u0105d i zako\u0144czenie strumienia<\/li>\n<li>complete \u2013 zako\u0144czenie strumienia<\/li>\n<li>subscribe \u2013 subskrybowa\u0107 strumie\u0144<\/li>\n<li>unsubscribe \u2013 wypisa\u0107 si\u0119 ze strumienia<\/li>\n<li>asObservable \u2013 przekszta\u0142camy w obserwatora<\/li>\n<li>toPromise \u2013 przekszta\u0142ca w promes\u0119<\/li>\n<\/ul>\n<p><\/p>\n<p>Wyr\u00f3\u017cnia si\u0119 4 5 typ\u00f3w subject\u00f3w. <\/p>\n<p>\n<b class=\"spoiler_title\">My\u015bli na g\u0142os<\/b><\/p>\n<p>Na streamie m\u00f3wi\u0142em 4, a okaza\u0142o si\u0119, \u017ce dodali jeszcze jeden. Jak to m\u00f3wi\u0105, \u017cyj i ucz si\u0119.<\/p>\n<p><\/p>\n<p>Prosty Subject <code>new Subject()<\/code>\u2013 najprostszy rodzaj subject\u00f3w. Tworzony bez parametr\u00f3w. Przesy\u0142a warto\u015bci, kt\u00f3re przychodz\u0105 tylko po subskrypcji.<\/p>\n<p><\/p>\n<p>BehaviorSubject <code>new BehaviorSubject(defaultData)<\/code> \u2013 moim zdaniem najpopularniejszy rodzaj subject\u00f3w. Przyjmuje na wej\u015bciu warto\u015b\u0107 domy\u015bln\u0105. Zawsze zachowuje dane ostatniego emitowanej, kt\u00f3re przesy\u0142a przy subskrypcji. Klasa ta ma r\u00f3wnie\u017c u\u017cyteczn\u0105 metod\u0119 value, kt\u00f3ra zwraca bie\u017c\u0105c\u0105 warto\u015b\u0107 strumienia.<\/p>\n<p><\/p>\n<p>ReplaySubject <code>new ReplaySubject(bufferSize?: number, windowTime?: number)<\/code> \u2013 Mo\u017ce opcjonalnie przyj\u0105\u0107 jako pierwszy argument rozmiar bufora warto\u015bci, kt\u00f3re b\u0119dzie przechowywa\u0107, a jako drugi czas, w kt\u00f3rym potrzebna jest zmiana.<\/p>\n<p><\/p>\n<p>AsyncSubject <code>new AsyncSubject()<\/code> \u2013 przy subskrypcji nic si\u0119 nie dzieje, a warto\u015b\u0107 zostanie zwr\u00f3cona tylko przy complete. Zwr\u00f3ci tylko ostatni\u0105 warto\u015b\u0107 strumienia.<\/p>\n<p><\/p>\n<p>WebSocketSubject <code>new WebSocketSubject(urlConfigOrSource: string | WebSocketSubjectConfig | Observable, destination?: Observer)<\/code> \u2013 O nim dokumentacja milczy i ja sam go widz\u0119 po raz pierwszy. Kto wie, co on robi, piszcie, uzupe\u0142nimy.<\/p>\n<p><\/p>\n<p>Uff. No c\u00f3\u017c, om\u00f3wili\u015bmy wszystko, co chcia\u0142em dzisiaj powiedzie\u0107. Mam nadziej\u0119, \u017ce te informacje by\u0142y pomocne. Samodzielnie mo\u017cna zapozna\u0107 si\u0119 z list\u0105 literatury w zak\u0142adce z przydatnymi informacjami.<\/p>\n<p><\/p>\n<h2 id=\"poleznaya-informaciya\">Przydatne informacje<\/h2>\n<p><\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/vk.com\/frontend_practice?w=wall-182297870_931\">https:\/\/vk.com\/frontend_practice?w=wall-182297870_931<\/a><\/noindex> \u2013 link do streamu<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/337042\/\">https:\/\/habr.com\/ru\/company\/ruvds\/blog\/337042\/<\/a><\/noindex> \u2013 Jak dzia\u0142a JS: przegl\u0105d silnika, mechanizm\u00f3w wykonywania, stosu wywo\u0142a\u0144<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/340508\/\">https:\/\/habr.com\/ru\/company\/ruvds\/blog\/340508<\/a><\/noindex> \u2014 Jak dzia\u0142a JS: cykl zdarze\u0144, asynchroniczno\u015b\u0107 i pi\u0119\u0107 sposob\u00f3w na popraw\u0119 kodu za pomoc\u0105 async \/ await<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/vanilla-js.blogspot.com\/2014\/09\/event-loop-javasript.html\">http:\/\/vanilla-js.blogspot.com\/2014\/09\/event-loop-javasript.html<\/a><\/noindex> \u2014 Jak dzia\u0142a Event Loop w JavaScript<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/tproger.ru\/translations\/asynchronous-javascript\/\">https:\/\/tproger.ru\/translations\/asynchronous-javascript\/<\/a><\/noindex> \u2014 Ewolucja asynchronicznego JavaScriptu<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/341880\/\">https:\/\/habr.com\/ru\/company\/ruvds\/blog\/341880\/<\/a><\/noindex> \u2014 Czym jest RxJS i dlaczego warto o nim wiedzie\u0107<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/medium.com\/ngx\/practical-use-rxjs-81aaab57045c\">https:\/\/medium.com\/ngx\/practical-use-rxjs-81aaab57045c<\/a><\/noindex> \u2014 Praktyczne zastosowanie RxJS<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/coursetro.com\/posts\/code\/148\/RxJS-Observables-Tutorial---Creating-&amp;-Subscribing-to-Observables\">https:\/\/coursetro.com\/posts\/code\/148\/RxJS-Observables-Tutorial&#8212;Creating-&amp;-Subscribing-to-Observables<\/a><\/noindex> \u2014 Samouczek RxJS Observables \u2014 Tworzenie i subskrypcja Observable\u2019\u00f3w<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/slides.com\/zenabsaleem\/rxjs-hot-cold-observables#\/\">https:\/\/slides.com\/zenabsaleem\/rxjs-hot-cold-observables#\/<\/a><\/noindex> \u2014 RXJS: Obserwowalne gor\u0105ce i zimne<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/clck.ru\/FiPgB\">https:\/\/clck.ru\/FiPgB<\/a><\/noindex> \u2014 Klasy, funkcje do tworzenia Observable. Operatory.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.learnrxjs.io\/operators\/\">https:\/\/www.learnrxjs.io\/operators\/<\/a><\/noindex> \u2014 Operatory RxJS z przyk\u0142adem<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/rxjs.dev\/api\">https:\/\/rxjs.dev\/api<\/a><\/noindex> \u2014 Lista API<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/clck.ru\/FkS8Y\">https:\/\/clck.ru\/FkS8Y<\/a><\/noindex> \u2014 Rodzaje Subject i harmonogramy w RxJS<\/li>\n<\/ul>\n<p>\u0179r\u00f3d\u0142o: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/462355\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442. \u041d\u0430 \u0441\u0432\u044f\u0437\u0438 \u041e\u043c\u0435\u043b\u044c\u043d\u0438\u0446\u043a\u0438\u0439 \u0421\u0435\u0440\u0433\u0435\u0439. \u041d\u0435 \u0442\u0430\u043a \u0434\u0430\u0432\u043d\u043e \u044f \u0432\u0435\u043b \u0441\u0442\u0440\u0438\u043c \u043f\u043e \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u043c\u0443 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e, \u0433\u0434\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b \u043f\u0440\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c \u0432 JavaScript. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u0431\u044b \u0445\u043e\u0442\u0435\u043b \u0437\u0430\u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b. \u041d\u043e \u043f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c \u043a\u0430\u043a \u043d\u0430\u0447\u0430\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0432\u043e\u0434\u043d\u0443\u044e. \u0418\u0442\u0430\u043a, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u0447\u043d\u0435\u043c \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0439: \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 \u0441\u0442\u0435\u043a \u0438 \u043e\u0447\u0435\u0440\u0435\u0434\u044c? \u0421\u0442\u0435\u043a \u2014 \u044d\u0442\u043e \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f, \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043a\u043e\u0442\u043e\u0440\u043e\u0439 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":27545,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[702],"tags":[],"class_list":["post-36774","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442. \u041d\u0430 \u0441\u0432\u044f\u0437\u0438 \u041e\u043c\u0435\u043b\u044c\u043d\u0438\u0446\u043a\u0438\u0439 \u0421\u0435\u0440\u0433\u0435\u0439. \u041d\u0435 \u0442\u0430\u043a \u0434\u0430\u0432\u043d\u043e \u044f \u0432\u0435\u043b \u0441\u0442\u0440\u0438\u043c \u043f\u043e \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u043c\u0443 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e, \u0433\u0434\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b \u043f\u0440\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c \u0432 JavaScript. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u0431\u044b \u0445\u043e\u0442\u0435\u043b \u0437\u0430\u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pl\/blog\/news\/asinhronnoe-programmirovanie-v-javascript-callback-promise-rxjs\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pl_PL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 JavaScript. ( Callback, Promise, RxJs ) | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442. \u041d\u0430 \u0441\u0432\u044f\u0437\u0438 \u041e\u043c\u0435\u043b\u044c\u043d\u0438\u0446\u043a\u0438\u0439 \u0421\u0435\u0440\u0433\u0435\u0439. \u041d\u0435 \u0442\u0430\u043a \u0434\u0430\u0432\u043d\u043e \u044f \u0432\u0435\u043b \u0441\u0442\u0440\u0438\u043c \u043f\u043e \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u043c\u0443 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e, \u0433\u0434\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b \u043f\u0440\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c \u0432 JavaScript. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u0431\u044b \u0445\u043e\u0442\u0435\u043b \u0437\u0430\u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pl\/blog\/news\/asinhronnoe-programmirovanie-v-javascript-callback-promise-rxjs\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:13:44+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:13:44+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Programowanie asynchroniczne w JavaScript. (Callback, Promise, RxJs) | ProHoster","description":"Cze\u015b\u0107 wszystkim. Z tej strony Omyelnitsky Sergey. Niedawno prowadzi\u0142em strumie\u0144 na temat programowania reaktywnego, gdzie opowiada\u0142em o asynchroniczno\u015bci w JavaScript. Dzi\u015b chcia\u0142bym podsumowa\u0107 ten materia\u0142.","canonical_url":"https:\/\/prohoster.info\/pl\/blog\/news\/asinhronnoe-programmirovanie-v-javascript-callback-promise-rxjs","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pl_PL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 JavaScript. ( Callback, Promise, RxJs ) | ProHoster","og:description":"\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442. \u041d\u0430 \u0441\u0432\u044f\u0437\u0438 \u041e\u043c\u0435\u043b\u044c\u043d\u0438\u0446\u043a\u0438\u0439 \u0421\u0435\u0440\u0433\u0435\u0439. \u041d\u0435 \u0442\u0430\u043a \u0434\u0430\u0432\u043d\u043e \u044f \u0432\u0435\u043b \u0441\u0442\u0440\u0438\u043c \u043f\u043e \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u043c\u0443 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e, \u0433\u0434\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b \u043f\u0440\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0441\u0442\u044c \u0432 JavaScript. \u0421\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u0431\u044b \u0445\u043e\u0442\u0435\u043b \u0437\u0430\u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b.","og:url":"https:\/\/prohoster.info\/pl\/blog\/news\/asinhronnoe-programmirovanie-v-javascript-callback-promise-rxjs","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:13:44+00:00","article:modified_time":"2019-10-31T19:13:44+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"36774","title":null,"description":null,"keywords":null,"keyphrases":{"focus":[],"additional":[]},"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-22 04:48:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:39:22","updated":"2026-08-11 12:50:32","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/36774","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=36774"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/36774\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/27545"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=36774"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=36774"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=36774"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}