{"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\/sl\/blog\/news\/asinhronnoe-programmirovanie-v-javascript-callback-promise-rxjs","title":{"rendered":"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Vsem pozdrav! Tukaj je Sergej Omelnitski. Nedavno sem imel prenos v \u017eivo o reaktivnem programiranju, kjer sem govoril o asinhronosti v JavaScriptu. Danes bi rad strnil to gradivo. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/11acf6af8328d3deb6f0ce48e813efb7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Preden za\u010dnemo s glavnim gradivom, potrebujemo uvod. Torej, za\u010dnimo z definicijami: kaj je sklad in kaj je vrsta?<br \/>\n<strong>Sklad <\/strong>je zbirka, katere elementi se obravnavajo po na\u010delu 'zadnji vstopil, prvi izstopil' LIFO.<br \/>\n<strong>Vrsta <\/strong>je zbirka, katere elementi se obravnavajo po na\u010delu 'prvi vstopil, prvi izstopil' FIFO.<\/p>\n<p><\/p>\n<p>Okej, nadaljujmo. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/a7d64d1c74f37b463869dd57b96c9d0e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>JavaScript je enovreten programski jezik. To pomeni, da obstaja le en tok izvajanja in en sklad, v katerega se funkcije dodajajo v vrsto za izvajanje. Zato lahko JavaScript v enem trenutku izvede le eno operacijo, druge operacije pa \u010dakajo na vrsto v skladu, dokler niso poklicane. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p><strong>Sklad klicev<\/strong> je podatkovna struktura, ki, poenostavljeno povedano, zabele\u017ei informacije o tem, kje smo v programu. Ko preidemo v funkcijo, v zgornji del sklada dodamo zapis o njej. Ko se iz funkcije vrnemo, vzamemo iz sklada najvi\u0161ji element in se vrnemo tja, od koder smo klicali to funkcijo. To je vse, kar sklad zmore. In zdaj se pojavi zelo zanimivo vpra\u0161anje. Kako torej deluje asinhronost v JavaScriptu?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/a29fd1dd3de06fb203c7dd14bda30548.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dejansko poleg sklada v brskalnikih obstaja posebna vrsta za delo s tako imenovanim WebAPI. Funkcije iz te vrste se izvr\u0161ijo po vrstnem redu \u0161ele po tem, ko je sklad popolnoma prazen. \u0160ele potem so premaknjene iz vrste v sklad za izvajanje. \u010ce je v skladu trenutno vsaj en element, potem ne morejo priti v sklad. Prav zato so klici funkcij z zamudo pogosto \u010dasovno neto\u010dni, ker funkcija ne more priti iz vrste v sklad, dokler je ta poln. <\/p>\n<p><\/p>\n<p>Poglejmo naslednji primer in se ukvarjajmo z njegovim 'izvajanjem' korak za korakom. Poleg tega bomo pogledali, kaj se pri tem dogaja v sistemu.<\/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=\"Asinhrono programiranje v JavaScriptu. (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 za\u010detku se ni\u010d ne dogaja. Konzola brskalnika je prazna, sklad klicev je prazen.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/4a16bbc23bade54ae0b02d81d5f6a581.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>2) Nato se ukaz console.log('Hi') doda v sklad klicev.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/a1845af23fd7dedebf94afc168f1f13f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>3) In se izvr\u0161i.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/57397b53386018b662f3a79a6d4d60fb.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>4) Nato se ukaz console.log('Hi') odstrani iz sklada klicev.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/7cb2b32be8807ecf39d2f38683ccd435.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>5) Zdaj gremo na ukaz setTimeout(function cb1() {\u2026 }). Ta se doda v sklad klicev.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/99c0724994e3390d009577852b451beb.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>6) Ukaz setTimeout(function cb1() {\u2026 }) se izvr\u0161i. Brskalnik ustvari \u010dasovnik, ki je del Web API. Ta bo izvajal od\u0161tevanje \u010dasa.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/99086cdeafd83c5fe72e92c4a9f9b738.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>7) Ukaz setTimeout(function cb1() {\u2026 }) kon\u010da svoje delo in se odstrani iz sklada klicev.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/24ac12b1b6cfbff780ece9e9a7acd7c7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>8) Ukaz console.log('Bye') se doda v sklad klicev.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/6ccad0ad8eebf05e870a409766d38766.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>9) Ukaz console.log('Bye') se izvede.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/09e4e380eb873fb23bea550f3ffb21f7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>10) Ukaz console.log('Bye') se odstrani iz sklada klicev.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/357bfb372361310681ba7bb1860d90d7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>11) Ko mine vsaj 5000 ms, \u010dasovnik kon\u010da svoje delo in doda povratni klic cb1 v vrsto povratnih klicev.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/8170e8ff5d3d0c56c0091658370c25cc.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>12) Dogodkovna zanka vzame funkcijo cb1 iz vrste povratnih klicev in jo doda v sklad klicev.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/d858a54e82bc32d84f854610db462bc1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>13) Funkcija cb1 se izvede in doda ukaz console.log('cb1') v sklad klicev.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/6ca8e016389904eec57035e64d57a157.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>14) Ukaz console.log('cb1') se izvede.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/0caa645a90ac1fca5fb8a76569494d48.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>15) Ukaz console.log('cb1') se odstrani iz sklada klicev.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/aeb838fe8df3f6e3f8603a4207a6e193.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>16) Funkcija cb1 se odstrani iz sklada klicev.<\/p>\n<p><\/p>\n<p>Poglejmo primer v dinamiki:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/3836d9df513afee374f498720990e39f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tako smo obravnavali, kako je asynchronicity izvedena v JavaScriptu. Zdaj pa hitro preidimo na evolucijo asinhronega kode.<\/p>\n<p><\/p>\n<h2 id=\"evolyuciya-asinhronnogo-koda\">Evolucija asinhronega kode.<\/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>Asinhrono programiranje, kakr\u0161nega poznamo v JavaScriptu, lahko izvedemo samo z funkcijami. Te lahko predamo drugim funkcijam, kot katerokoli drugo spremenljivko. Tako so nastali povratni klici. In to je zabavno, dokler se ne spremeni v \u017ealost, obup in \u017ealost. Zakaj? Preprosto:<\/p>\n<p><\/p>\n<ul>\n<li>S pove\u010devanjem zapletenosti kode se projekt hitro spremeni v malo razumljive ve\u010dkratno utele\u0161ene bloke \u2014 \"callback hell\".<\/li>\n<li>Obravnavo napak je enostavno spregledati.<\/li>\n<li>Izrazov s return ni mogo\u010de vra\u010dati.<\/li>\n<\/ul>\n<p><\/p>\n<p>S pojavom Promise se je stanje nekoliko izbolj\u0161alo.<\/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>Pojavili so se verigi obljub, kar je izbolj\u0161alo berljivost kode.<\/li>\n<li>Pojavil se je poseben na\u010din za zajemanje napak.<\/li>\n<li>Pojavila se mogu\u0107nost paralelnog izvr\u0161avanja uz pomo\u0107 Promise.all<\/li>\n<li>Ugnije\u017edenu asinhronost mo\u017eemo re\u0161iti pomo\u0107u async\/await<\/li>\n<\/ul>\n<p><\/p>\n<p>Ali obe\u0107anje ima svoja ograni\u010denja. Na primer, obe\u0107anje se ne mo\u017ee otkazati bez dodatnih trikova, a najva\u017enije \u2014 radi sa jednom vredno\u0161\u0107u.<\/p>\n<p><\/p>\n<p>Pa, polako smo do\u0161li do reaktivnog programiranja. Umorni ste? Pa dobro, mo\u017eete da skuvate \u010daj, malo razmislite i vratite se da \u010ditate dalje. A ja \u0107u nastaviti.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/48409ec625d57fec171214c1de332c85.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Reaktivno programiranje<\/strong>\u2014 paradigma programiranja usmerena na tokove podataka i \u0161irenje promena. Hajde da detaljnije razjasnimo \u0161ta je to tok podataka.<\/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>Zamislimo da imamo polje za unos. Kreiramo niz, i na svaki keyup doga\u0111aj input-a \u0107emo \u010duvati doga\u0111aj u na\u0161em nizu. Pri tome, \u017eeleo bih da napomenem da je na\u0161 niz sortiran po vremenu \u2014 tj. indeks kasnijih doga\u0111aja je ve\u0107i od indeksa ranijih. Takav niz predstavlja pojednostavljeni model toka podataka, ali to jo\u0161 nije tok. Da bi se ovaj niz mogao smatrati tokom, on mora nekako obavestiti pretplatnike da su mu novi podaci dostupni. Tako smo do\u0161li do definicije toka.<\/p>\n<p><\/p>\n<h3 id=\"potok-dannyh\">Tok podataka<\/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=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/68ec447abafb6b8a323b429ed94f8252.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Tok<\/strong>\u2014 to je niz podataka, sortiranih po vremenu, koji mo\u017ee obavestiti da su se podaci promenili. A sada zamislite koliko je zgodno pisati kod u kojem \u0107e jedno dejstvo zahtevati nekoliko doga\u0111aja na razli\u010ditim mestima u kodu. Jednostavno se pretplatimo na tok i on \u0107e nam sam javiti kada do\u0111e do promena. I to mo\u017ee da uradi biblioteka RxJs.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (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 je biblioteka za rad sa asinhronim i doga\u0111ajima zasnovanim programima koriste\u0107i posmatrane nizove. Biblioteka pru\u017ea osnovni tip <em>Observable<\/em>, nekoliko pomo\u0107nih tipova (<em>Observer, Schedulers, Subjects<\/em>) i operatore za rad sa doga\u0111ajima kao kolekcijama (<em>map, filter, reduce, every<\/em> i sli\u010dne iz JavaScript Array).<\/p>\n<p><\/p>\n<p>Hajde da se upoznamo sa osnovnim pojmovima ove biblioteke.<\/p>\n<p><\/p>\n<h3 id=\"observable-observer-producer\">Observable, Observer, Producer<\/h3>\n<p><\/p>\n<p>Observable \u2014 prvi osnovni tip koji \u0107emo razmotriti. Ova klasa sadr\u017ei ve\u0107inu implementacije RxJs. Povezana je sa posmatranim tokom na koji se mo\u017ee pretplatiti koriste\u0107i metodu subscribe.<\/p>\n<p><\/p>\n<p>U Observable se implementira pomo\u0107ni mehanizam za kreiranje a\u017euriranja, koji se naziva <em>Observer<\/em>. Izvor vrednosti za Observer naziva se <em>Producer<\/em>. To mo\u017ee biti niz, iterator, web socket, neki doga\u0111aj itd. Tako da mo\u017eemo re\u0107i da je observable posrednik izme\u0111u Producer i Observer. <\/p>\n<p><\/p>\n<p>Observable obra\u0111uje tri vrste doga\u0111aja Observer:<\/p>\n<p><\/p>\n<ul>\n<li>next \u2013 novi podaci<\/li>\n<li>error \u2013 gre\u0161ka, ako je sekvenca okon\u010dana zbog izuzetne situacije. Ovaj doga\u0111aj tako\u0111e podrazumeva zavr\u0161etak sekvence.<\/li>\n<li>complete \u2014 signal o zavr\u0161etku sekvence. To zna\u010di da novih podataka vi\u0161e ne\u0107e biti.<\/li>\n<\/ul>\n<p><\/p>\n<p>Pogledajmo demo:<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/c5bcd2af0f18b6de3ab0dbc20db595d1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Na po\u010detku \u0107emo obraditi vrednosti 1, 2, 3, a nakon 1 sekunde dobi\u0107emo 4 i zavr\u0161iti na\u0161 tok.<\/p>\n<p>\n<b class=\"spoiler_title\">Misli naglas<\/b><\/p>\n<p>I tada sam shvatio da je pri\u010danje bilo zanimljivije od pisanja o tome. \ud83d\ude00 <\/p>\n<p><\/p>\n<h3 id=\"subscription\">Subscription<\/h3>\n<p><\/p>\n<p>Kada se pretplatimo na tok, kreiramo novu klasu <strong>subscription<\/strong>, koja nam omogu\u0107ava da otka\u017eemo pretplatu koriste\u0107i metodu <em>unsubscribe<\/em>. Tako\u0111e mo\u017eemo grupisati pretplate koriste\u0107i metodu <em>add<\/em>. Logi\u010dno je da mo\u017eemo razgrupisati tokove koriste\u0107i <em>remove<\/em>. Metodi add i remove uzimaju drugu pretplatu kao ulaz. Vredno je napomenuti da kada otka\u017eemo pretplatu, otkazujemo se od svih podre\u0111enih pretplata kao da smo i njima pozvali metodu unsubscribe. Idemo dalje.<\/p>\n<p><\/p>\n<h3 id=\"vidy-potokov\">Vrste tokova<\/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>Producer se kreira spolja observable-a<\/td>\n<td>Producer se kreira unutar observable-a<\/td>\n<\/tr>\n<tr>\n<td>Podaci se prenose u trenutku kreiranja observable-a<\/td>\n<td>Podaci se dostavljaju u trenutku pretplate<\/td>\n<\/tr>\n<tr>\n<td>Potrebna je dodatna logika za otkazivanje pretplate<\/td>\n<td>Tok se zavr\u0161ava samostalno<\/td>\n<\/tr>\n<tr>\n<td>Koristi vezu jedan-ka-vi\u0161e<\/td>\n<td>Koristi vezu jedan-na-jedan<\/td>\n<\/tr>\n<tr>\n<td>Sve pretplate imaju jedinstvenu vrednost<\/td>\n<td>Pretplate su nezavisne<\/td>\n<\/tr>\n<tr>\n<td>Podaci se mogu izgubiti ako nema pretplate<\/td>\n<td>Ponovo objavljuje sve vrednosti toka za novu pretplatu<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><\/p>\n<p>\u010ce potegnemo analogijo, bi vro\u010d tok predstavil kot film v kinu. Od trenutka, ko si pri\u0161el, za\u010dne\u0161 ogled. Hladen tok bi primerjal z klicem v tehni\u010dno podporo. Vsak, ki pokli\u010de, poslu\u0161a posnetek avtomatskega odgovora od za\u010detka do konca, vendar lahko prekine klic s pomo\u010djo unsubscribe.<\/p>\n<p><\/p>\n<p>Rad bi opozoril, da obstajajo tudi tako imenovani topli tokovi (to definicijo sem sre\u010dal zelo redko in le v tujih skupnostih) \u2014 to je tok, ki se transformira iz hladnega v vro\u010dega. Pojavi se vpra\u0161anje \u2014 kje ga uporabiti)) Prikazal bom primer iz prakse.<\/p>\n<p><\/p>\n<p>Delam z Angularem. Aktivno uporablja rxjs. Za pridobivanje podatkov na stre\u017eniku pri\u010dakujem hladen tok in ta tok uporabljam v predlogi s pomo\u010djo asyncPipe. \u010ce uporabljam to cev ve\u010dkrat, se vrnem k definiciji hladnega toka, vsaka cev bo zahtevala podatke s stre\u017enika, kar je milo re\u010deno nenavadno. \u010ce pa spremenim hladen tok v topli, bo zahteva izvedena enkrat.<\/p>\n<p><\/p>\n<p>Dejansko je razumevanje vrst tokov precej zapleteno za za\u010detnike, vendar je pomembno. <\/p>\n<p><\/p>\n<h3 id=\"operators\">Operaterji<\/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\u017enosti za delo s tokovi nam ponujajo operaterji. Ti pomagajo nadzorovati dogodke, ki se odvijajo v Observable. Oglejali si bomo nekaj najbolj priljubljenih, podrobneje pa se lahko seznanite z operaterji prek povezav v koristnih informacijah.<\/p>\n<p><\/p>\n<p><strong>Operaterji \u2014 of<\/strong><\/p>\n<p><\/p>\n<p>Za\u010dnimo s pomo\u017enim operaterjem of. Ustvari Observable na osnovi preproste vrednosti.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/68f382447e306392b025867a9a1e88e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Operaterji \u2014 filter<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/24ac65fdb5ccc7f6301b3dfe49f1e804.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Operater filtriranja filter, kot lahko razumemo iz imena, filtrira signal toka. \u010ce operater vrne resnico, ga naprej spusti.<\/p>\n<p><\/p>\n<p><strong>Operaterji \u2014 take<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (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 sprejme \u0161tevilo emitov, po katerem zaklju\u010di tok.<\/p>\n<p><\/p>\n<p><strong>Operaterji \u2014 debounceTime<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (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 zavr\u017ee izpu\u0161\u010dene vrednosti, ki pridejo v dolo\u010denem \u010dasovnem okviru med izhodnimi podatki \u2014 po preteku \u010dasovnega intervala izpusti zadnjo vrednost.<\/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  \/\/ \u0418\u0437\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0437 \u0432 1000\u043c\u0441\n  setInterval(() =&gt; {\n    observer.next(i++)\n  }, 1000);\n\n  \/\/ \u0418\u0437\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0437 \u0432 1500\u043c\u0441\n  setInterval(() =&gt; {\n    observer.next(i++)\n  }, 1500);\n}).pipe(\n  debounceTime(700),  \/\/ \u0416\u0434\u0435\u043c 700\u043c\u0441 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439\n  take(3)\n);  <\/code><\/pre>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/dbb690d6fea6c43c1f0a2bdabea57934.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>\u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u2014 takeWhile<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/120d9fe6ddf5a60ddffc8742989b27ff.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>\u0418\u0437\u043b\u0443\u0447\u0430\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043f\u043e\u043a\u0430 takeWhile \u043d\u0435 \u0432\u0435\u0440\u043d\u0435\u0442 false, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043e\u0442\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u043f\u043e\u0442\u043e\u043a\u0430.<\/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  \/\/ \u0418\u0437\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0437 \u0432 1000\u043c\u0441\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=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/d2910d1bf9fab228acc9241fdbad3d4a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>\u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u2014 combineLatest<\/strong><\/p>\n<p><\/p>\n<p>\u041a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 combineLatest \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 promise.all. \u041e\u043d \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0432 \u043e\u0434\u0438\u043d. \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u043f\u043e\u0442\u043e\u043a \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442 \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u043d\u043e \u0438\u0437\u043b\u0443\u0447\u0435\u043d\u0438\u0435, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043e\u0442 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0432 \u0432\u0438\u0434\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u0430. \u041f\u043e\u0441\u043b\u0435 \u043b\u044e\u0431\u043e\u0433\u043e \u043d\u043e\u0432\u043e\u0433\u043e \u0438\u0437\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0451\u043d\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (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  \/\/ \u0418\u0437\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0437 \u0432 1000\u043c\u0441\n  setInterval(() =&gt; {\n    observer.next('a: ' + i++);\n  }, 1000);\n});\n\nconst observer_2 = Observable.create((observer) =&gt; {\n  let i = 1;\n  \/\/ \u0418\u0437\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0437 \u0432 750\u043c\u0441\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=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/7fc35461f446987ef81302ff7c2ed5a8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>\u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u2014 zip<\/strong><\/p>\n<p><\/p>\n<p>Zip \u2014 \u0436\u0434\u0451\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438\u0437 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u044d\u0442\u0438\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439. \u0415\u0441\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0442 \u0438\u0437 \u043a\u0430\u043a\u043e\u0433\u043e-\u043b\u0438\u0431\u043e \u043f\u043e\u0442\u043e\u043a\u0430, \u0442\u043e \u0433\u0440\u0443\u043f\u043f\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0430.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (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  \/\/ \u0418\u0437\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0437 \u0432 1000\u043c\u0441\n  setInterval(() =&gt; {\n    observer.next('a: ' + i++);\n  }, 1000);\n});\n\nconst observer_2 = Observable.create((observer) =&gt; {\n  let i = 1;\n  \/\/ \u0418\u0437\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0437 \u0432 750\u043c\u0441\n  setInterval(() =&gt; {\n    observer.next('b: ' + i++);\n  }, 750);\n});\n\nconst observer_3 = Observable.create((observer) =&gt; {\n  let i = 1;\n  \/\/ \u0418\u0437\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0437 \u0432 500\u043c\u0441\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=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/e2606bf8ea5f8a660699ebe896a27d80.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>\u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u2014 forkJoin<\/strong><\/p>\n<p><\/p>\n<p>forkJoin \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u043f\u043e\u0442\u043e\u043a\u0438, \u043d\u043e \u043e\u043d \u0438\u0437\u043b\u0443\u0447\u0430\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0433\u0434\u0430 \u0432\u0441\u0435 \u043f\u043e\u0442\u043e\u043a\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u044b (complete).<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (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  \/\/ Emitting 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  \/\/ Emitting 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  \/\/ Emitting 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=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/df110efc7ece46fc1d8da2d7693f75bb.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Operatorji \u2014 map<\/strong><\/p>\n<p><\/p>\n<p>Operator transformacije map pretvara emitovanu vrednost u novu. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (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  \/\/ Emitting 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=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/4e4ff3e2eb4acf69f16559c711a2e666.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><strong>Operatorji \u2013 share, tap<\/strong><\/p>\n<p><\/p>\n<p>Operator tap omogo\u010da izvajanje stranskih u\u010dinkov, torej kakr\u0161na koli dejanja, ki ne vplivajo na zaporedje.<\/p>\n<p><\/p>\n<p>Utility operator share mo\u017ee pretvoriti hladan tok u vru\u0107. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Asinhrono programiranje v JavaScriptu. (Callback, Promise, RxJs)\" src=\"\/wp-content\/uploads\/2019\/08\/c46e96420ed78d197ceef829ff74c82d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Sa operatorima smo zavr\u0161ili. Prelazimo na Subject.<\/p>\n<p>\n<b class=\"spoiler_title\">Misli naglas<\/b><\/p>\n<p>I onda sam oti\u0161ao da pijem \u010daj. Umorili su me ovi primeri \ud83d\ude00<\/p>\n<p><\/p>\n<h2 id=\"semeystvo-subject-ov\">Familija subject-ova<\/h2>\n<p><\/p>\n<p>Familija subject-ova je \u017eivopisan primer vru\u0107ih tokova. Ove klase su neka vrsta hibrida, koje deluju istovremeno kao observable i observer. Po\u0161to je subject vru\u0107i tok, potrebno je odjaviti se od njega. Ako govorimo o osnovnim metodama, to su:<\/p>\n<p><\/p>\n<ul>\n<li>next \u2013 prenos novih podataka u tok<\/li>\n<li>error \u2013 gre\u0161ka i zavr\u0161etak toka<\/li>\n<li>complete \u2013 zavr\u0161etak toka<\/li>\n<li>subscribe \u2013 pretplatiti se na tok<\/li>\n<li>unsubscribe \u2013 odjaviti se od toka<\/li>\n<li>asObservable \u2013 transformi\u0161emo u posmatra\u010da<\/li>\n<li>toPromise \u2013 transformi\u0161e u promise<\/li>\n<\/ul>\n<p><\/p>\n<p>Izdvajamo 4 do 5 tipova subject-ova. <\/p>\n<p>\n<b class=\"spoiler_title\">Misli naglas<\/b><\/p>\n<p>Na streamu sam govorio o 4, a ispostavilo se da su dodali jo\u0161 jedan. Kao \u0161to ka\u017eu, vek \u017eivi vek u\u010di.<\/p>\n<p><\/p>\n<p>Obi\u010dan Subject <code>new Subject()<\/code>\u2013 najjednostavnija vrsta subject-ova. Kreira se bez parametara. Prenosi vrednosti koje su stigle samo nakon pretplate.<\/p>\n<p><\/p>\n<p>BehaviorSubject <code>new BehaviorSubject( defaultData )<\/code> \u2013 po mom mi\u0161ljenju, najra\u0161irenija vrsta subject-ova. Prima vrednost po default-u. Uvek \u010duva podatke poslednjeg emita, koje prenosi pri pretplati. Ova klasa tako\u0111e ima korisnu metodu value, koja vra\u0107a trenutnu vrednost toka.<\/p>\n<p><\/p>\n<p>ReplaySubject <code>new ReplaySubject(bufferSize?: number, windowTime?: number)<\/code> \u2014 Na ulazu mo\u017ee opcionalno primiti prvi argument kao veli\u010dinu baferiraju\u0107e vrednosti koju \u0107e \u010duvati, a drugi kao vreme tokom kojeg su nam potrebne izmenjene vrednosti.<\/p>\n<p><\/p>\n<p>AsyncSubject <code>novi AsyncSubject()<\/code> \u2014 pri naro\u010danju se ni\u010d ne zgodi, vrednost pa bo vrnjena le ob complete. Vrnjena bo le zadnja vrednost toka.<\/p>\n<p><\/p>\n<p>WebSocketSubject <code>nov WebSocketSubject(urlConfigOrSource: string | WebSocketSubjectConfig&lt;T&gt; | Observable&lt;T&gt;, destination?: Observer&lt;T&gt;)<\/code> \u2014 O njem dokumentacija mol\u010di in ga prvi\u010d vidim. Kdor ve, kaj po\u010dne, naj pi\u0161e, dopolnimo.<\/p>\n<p><\/p>\n<p>Uff. No, pregledali smo vse, kar sem \u017eelel danes povedati. Upam, da so bile te informacije koristne. Seznam literature si lahko ogledate v zavihku uporabne informacije.<\/p>\n<p><\/p>\n<h2 id=\"poleznaya-informaciya\">Uporabne informacije<\/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> \u2014 povezava na stream<\/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> \u2014 Kako deluje JS: pregled motorja, mehanizmov izvajanja, sklada klicev<\/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 Kako deluje JS: cikel dogodkov, asinhronost in pet na\u010dinov za izbolj\u0161anje kode s pomo\u010djo 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 Kako deluje Event Loop v JavaScriptu<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/tproger.ru\/translations\/asynchronous-javascript\/\">https:\/\/tproger.ru\/translations\/asynchronous-javascript\/<\/a><\/noindex> \u2014 Evolucija asinhronega JavaScript<\/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 Kaj je RxJS in zakaj je koristno vedeti zanj<\/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 Prakti\u010dna uporaba 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 RxJS Observables Tutorial \u2014 Ustvarjanje in naro\u010danje na Observables<\/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: Vro\u010de in hladne observables<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/clck.ru\/FiPgB\">https:\/\/clck.ru\/FiPgB<\/a><\/noindex> \u2014 Razredi in funkcije za ustvarjanje Observable. Operatorji.<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.learnrxjs.io\/operators\/\">https:\/\/www.learnrxjs.io\/operators\/<\/a><\/noindex> \u2014 RxJS Operatorji po exempelih<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/rxjs.dev\/api\">https:\/\/rxjs.dev\/api<\/a><\/noindex> \u2014 Seznam API-jev<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/clck.ru\/FkS8Y\">https:\/\/clck.ru\/FkS8Y<\/a><\/noindex> \u2014 Vrste Subject in Razporedi v RxJS<\/li>\n<\/ul>\n<p>Izvor: <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.4 - 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\/sl\/blog\/news\/asinhronnoe-programmirovanie-v-javascript-callback-promise-rxjs\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"sl_SI\" \/>\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\/sl\/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\udd47Asinhrono programiranje v JavaScriptu. ( Callback, Promise, RxJs ) | ProHoster","description":"Vsem pozdrav! Tukaj je Sergej Omelnitski. Nedavno sem imel prenos v \u017eivo o reaktivnem programiranju, kjer sem govoril o asinhronosti v JavaScriptu. Danes bi rad strnil to gradivo.","canonical_url":"https:\/\/prohoster.info\/sl\/blog\/news\/asinhronnoe-programmirovanie-v-javascript-callback-promise-rxjs","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sl_SI","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\/sl\/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\/sl\/wp-json\/wp\/v2\/posts\/36774","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/comments?post=36774"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/posts\/36774\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/media\/27545"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/media?parent=36774"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/categories?post=36774"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sl\/wp-json\/wp\/v2\/tags?post=36774"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}