日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

使用 RxJS 实现 JavaScript 的 Reactive 编程

發(fā)布時(shí)間:2023/12/4 javascript 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用 RxJS 实现 JavaScript 的 Reactive 编程 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

簡(jiǎn)介

作為有經(jīng)驗(yàn)的JavaScript開(kāi)發(fā)者,我們會(huì)在代碼中采用一定程度的異步代碼。我們不斷地處理用戶的輸入請(qǐng)求,也從遠(yuǎn)程獲取數(shù)據(jù),或者同時(shí)運(yùn)行耗時(shí)的計(jì)算任務(wù),所有這些都不能讓瀏覽器崩潰。可以說(shuō),這些都不是瑣碎的任務(wù),它是確切的需求,我們學(xué)著去避開(kāi)同步計(jì)算,讓模型的時(shí)間和延時(shí)成為問(wèn)題的關(guān)鍵。對(duì)于簡(jiǎn)單的應(yīng)用程序,直接使用JavaScript的主事件系統(tǒng),甚至使用jQuery庫(kù)幫助也很常見(jiàn)。然而,還沒(méi)有適當(dāng)?shù)哪J絹?lái)擴(kuò)展的簡(jiǎn)單代碼,解決這些異步問(wèn)題,滿足更豐富的應(yīng)用特性,滿足現(xiàn)代web用戶的需求,這些仍然是困難的。我們?cè)絹?lái)越發(fā)現(xiàn)我們的應(yīng)用代碼正變得復(fù)雜,難以維護(hù),難以測(cè)試。問(wèn)題的本質(zhì)是異步計(jì)算本身就是難以管理的,而RxJS可以解決這個(gè)問(wèn)題。

RxJS解決的問(wèn)題

任何應(yīng)用最重要的一個(gè)目標(biāo)之一就是在所有時(shí)刻保持響應(yīng)。這意味著對(duì)于一個(gè)應(yīng)用來(lái)說(shuō)當(dāng)它在處理用戶輸入或者憑借AJAX從服務(wù)器接受一些額外的數(shù)據(jù)時(shí)停止是一件不可接受的事情。通常來(lái)說(shuō),主要的問(wèn)題是IO(輸入/輸出)運(yùn)行(從磁盤(pán)或者網(wǎng)絡(luò)讀取)比CPU執(zhí)行指令慢太多。這同時(shí)實(shí)用于客戶端和服務(wù)器端。讓我門(mén)來(lái)看看客戶端。在JavaScript中,解決問(wèn)題的方案始終是充分利用瀏覽器的多重連接并且用回調(diào)函數(shù)來(lái)大量產(chǎn)生一個(gè)獨(dú)立的用來(lái)照顧一些長(zhǎng)期運(yùn)行的處理。這是一種反轉(zhuǎn)控制控制形式,因?yàn)槌绦虻目刂撇皇潜荒悴倏v的(因?yàn)槟悴荒茴A(yù)知某一處理什么時(shí)候會(huì)完成),而是在運(yùn)行時(shí)間的責(zé)任下交還給你的。雖然對(duì)于小應(yīng)用程序非常有用,但回調(diào)的使用使內(nèi)容豐富的大型應(yīng)用變得凌亂,它需要同時(shí)處理的數(shù)據(jù)來(lái)自用戶以及遠(yuǎn)程HTTP的調(diào)用。我們都有過(guò)這樣的經(jīng)歷:一旦你需要多塊數(shù)據(jù)時(shí)你就陷入了流行的”末日金字塔“或者回調(diào)地獄。

?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 makeHttpCall( '/items' ,? ??? items?=>?{ ?????? for? (itemId?of?items)?{ ????????? makeHttpCall(`/items/${itemId}/info`, ??????????? itemInfo?=>?{???????? ?????????????? makeHttpCall(`/items/${itemInfo.pic}`, ???????????????? img?=>?{ ???????????????????? showImg(img); ?????????????? });??? ??????????? }); ?????? } }); beginUiRendering();

這段代碼有很多的問(wèn)題。 其中之一就是風(fēng)格。當(dāng)你在這些嵌套的回調(diào)函數(shù)中添加越來(lái)越多的邏輯,這段代碼就會(huì)變得很復(fù)雜很難理解。因?yàn)檠h(huán)還產(chǎn)生了一個(gè)更加細(xì)微的問(wèn)題。for循環(huán)是同步的控制流語(yǔ)句,這并不能很好的配合異步調(diào)用,因?yàn)闀?huì)有延遲,這可能會(huì)產(chǎn)生很奇怪的bug。

這個(gè)問(wèn)題一直都是JavaScript開(kāi)發(fā)者的大麻煩,所以JavaScript在SE6中引入了Promises。?Promises幫助開(kāi)發(fā)者解決這些類似的問(wèn)題,它提供了一個(gè)非常流暢的接口來(lái)捕獲時(shí)間并且提供一個(gè)回調(diào)方法then()。上面的代碼就變成了:

?

1 2 3 4 makeHttpCall( '/items' ) ???? .then(itemId?=>?makeHttpCall(`/items/${itemId}/info`)) ???? .then(itemInfo?=>?makeHttpCall(`/items/${itemInfo}.pic}`)) ???? .then(showImg);

這毫無(wú)疑問(wèn)是一個(gè)進(jìn)步。理解這段代碼的難度顯著下降。然而,盡管Promises在處理這種單值(或單個(gè)錯(cuò)誤)時(shí)非常高效,它有也一些局限性。Promimses在處理用戶連續(xù)輸入的數(shù)據(jù)流時(shí)效率怎么樣呢? 這時(shí)Promises處理起來(lái)也并不高效,因?yàn)樗鼪](méi)有事件的刪除、分配、重試等等的語(yǔ)法定義。接下來(lái)開(kāi)始講解RxJS。

RxJS 初探

RxJS是一個(gè)解決異步問(wèn)題的JS開(kāi)發(fā)庫(kù).它起源于?Reactive Extensions?項(xiàng)目,它帶來(lái)了觀察者模式和函數(shù)式編程的相結(jié)合的最佳實(shí)踐。 觀察者模式是一個(gè)被實(shí)踐證明的模式,基于生產(chǎn)者(事件的創(chuàng)建者)和消費(fèi)者(事件的監(jiān)聽(tīng)者)的邏輯分離關(guān)系.

況且函數(shù)式編程方式的引入,如說(shuō)明性編程,不可變數(shù)據(jù)結(jié)構(gòu),鏈?zhǔn)椒椒ㄕ{(diào)用會(huì)使你極大的簡(jiǎn)化代碼量。(和回調(diào)代碼方式說(shuō)再見(jiàn)吧)。

若想仔細(xì)了解函數(shù)式編程,請(qǐng)?jiān)L問(wèn)這里(the Functional?Programming in JavaScript RefCard?)。

如果你熟悉了函數(shù)式編程,請(qǐng)把RxJS理解為異步化的Underscore.js。

RxJS 引入了一個(gè)重要的數(shù)據(jù)類型——流(stream)。

理解流( Streams)

流(Streams)無(wú)非是隨時(shí)間流逝的一系列事件。流(Streams)可以用來(lái)處理任何類型的事件,如:鼠標(biāo)點(diǎn)擊,鍵盤(pán)按下,網(wǎng)絡(luò)位數(shù)據(jù),等等。你可以把流作為變量,它有能力從數(shù)據(jù)角度對(duì)發(fā)生的改變做出反應(yīng)。

變量和流都是動(dòng)態(tài)的,但表現(xiàn)有些不同;為了理解它,讓我們看一個(gè)簡(jiǎn)單的例子。考慮以下簡(jiǎn)單的算術(shù)運(yùn)算:

?

1 2 3 4 5 6 7 var? a?=?2; var? b?=?4; var? c?=?a?+?b; console.log(c);? //->?6 a?=?10;?? //?reassign?a console.log(c);? //->?still?6
無(wú)若
翻譯于 8個(gè)月前

1人頂

?翻譯的不錯(cuò)哦!

盡管變量a變?yōu)榱?0,但這是一種通過(guò)設(shè)計(jì)方式保證所依賴的變量不變。這就是最大的不同。事件引發(fā)的改變總是從事件源(生產(chǎn)者)
向下傳遞到所有事件監(jiān)聽(tīng)方(消費(fèi)者)。假如說(shuō)把變量看成流,下面就會(huì)這樣:

?

1 2 3 4 5 6 7 var? A$?=?2; var? B$?=?4; var? C$?=?A$?+?B$; console.log(C$);? //->?6 A$?=?10;?? console.log(C$);? //->??16

這樣你看到了,流的方式重新定義的變量值的動(dòng)態(tài)行為。(作為習(xí)慣,我喜歡使用$符號(hào)在流變量命名里)
換句話說(shuō),C$是把兩個(gè)流變量A$和B$進(jìn)行合并操作。當(dāng)一個(gè)新值被推進(jìn)了A$,C$立刻響應(yīng)式的變更為16。當(dāng)前這只是一個(gè)
牽強(qiáng)的例子,距離真正的語(yǔ)法還很遠(yuǎn)。這個(gè)例子解釋了變量在事件流中的變化過(guò)程。

現(xiàn)在讓我們開(kāi)始學(xué)習(xí)RxJS。

可觀察數(shù)據(jù)類型

或許RxJS庫(kù)最重要的部分是可觀察數(shù)據(jù)類型的定義。這種類型被用于包裝一個(gè)數(shù)據(jù)片段(按鈕事件,鍵盤(pán)事件,鼠標(biāo)事件,數(shù)字,字符串或者隊(duì)列),這樣它就有了流式數(shù)據(jù)類型的優(yōu)點(diǎn)。最簡(jiǎn)單的觀察對(duì)象是這種單變量形式,例如:

?

1 var? streamA$?=?Rx.Observable.of(2);

我們重新使用上面的例子,這次是真正的RxJS語(yǔ)法。這回使用了新的API,我要詳細(xì)的講一下:

?

1 2 3 4 5 6 const?streamA$?=?Rx.Observable.of(2); const?streamB$?=?Rx.Observable.of(4); const?streamC$?=?Rx.Observable.concat(streamA$,?streamB$) ?? .reduce((x,?y)?=>?x??+?y); streamC$.subscribe(console.log);? //prints?6

運(yùn)行這個(gè)例子輸出值為6。不像之前的偽代碼,在變量被定義后實(shí)際上不能對(duì)流對(duì)象重新賦值。如何必須那樣做的話就要重新創(chuàng)建一個(gè)新的流變量,因?yàn)榱髯兞渴遣豢勺兊臄?shù)據(jù)類型。既然是不可變的,通常我們可以安全的使用ES6規(guī)范里的不可變關(guān)鍵字const使代碼更清晰明確。

為了給streamA$推一系列新值,你必須改變streamA$定義的方式:

?

1 2 3 const?streamA$?=?Rx.Observable.of(2,?10) ... streamC$.subscribe(console.log);? //prints?16

現(xiàn)在訂閱streamC$將會(huì)得到值16。就像我之前提到的,流只是一個(gè)在時(shí)間軸上的事件傳輸序列。以下是可視化圖例。

創(chuàng)建可觀察序列對(duì)象

很多不同的方法都可以創(chuàng)建可觀察序列對(duì)象。這里是一些普通使用的例子:

方法
說(shuō)明
of(arg)把參數(shù)轉(zhuǎn)換成可觀察序列對(duì)象
from(iterable)把可迭代的隊(duì)列參數(shù)轉(zhuǎn)換成可觀察序列對(duì)象
fromPromise(promise)把promise對(duì)象參數(shù)轉(zhuǎn)換成可觀察序列對(duì)象
fromEvent(element, eventName)通過(guò)增加一個(gè)事件監(jiān)聽(tīng)器用于監(jiān)聽(tīng)匹配的Dom元素,jQuery元素,Zepto元素,Angular元素,Ember.js元素或者EventEmitter等,
來(lái)創(chuàng)建可觀察序列對(duì)象

流式編程的另一個(gè)不同點(diǎn)是觸發(fā)機(jī)制。可觀察序列類型對(duì)象是后觸發(fā)的(lazy data types),就是說(shuō)當(dāng)有訂閱者訂閱的時(shí)候什么也不執(zhí)行(這種方式不會(huì)有事件發(fā)出來(lái))。它的訂閱機(jī)制是被觀察者(Observer)觸發(fā)的。

觀察者(Observer)

觀察者代表模型的消費(fèi)者一端。它負(fù)責(zé)被可觀察序列對(duì)象發(fā)送過(guò)來(lái)的值進(jìn)行處理和反饋。觀察者的API簡(jiǎn)單,基于迭代者模式它定義了
next方法。當(dāng)事件執(zhí)行結(jié)果推向到可觀察對(duì)象的時(shí)候,這個(gè)方法就會(huì)被調(diào)用。之前streamC$.subscribe(console.log) 這種簡(jiǎn)寫(xiě)的方式,其實(shí)就是背后創(chuàng)建了觀察者對(duì)象(Observer)。創(chuàng)建的過(guò)程如下:

?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 const?observer?=?Rx.Observer.create( ???? function? next(val)?{?? ???????? console.log(val); ???? }, ???? function? error(err)?{? ???????? ;? //?事件異常情況執(zhí)行 ???? }, ???? function? complete()?{ ???????? ;? // 事件完成后執(zhí)行 ???? } );

觀察者也定義了處理異常的API,意味著會(huì)發(fā)出執(zhí)行過(guò)程中的異常信號(hào)通知。所有的觀察者對(duì)象里的方法都是可選擇的,其實(shí)你只需要
訂閱一下就可以(調(diào)用subscribe方法)。最普遍的方式是需要提供一下對(duì)應(yīng)的業(yè)務(wù)方法映射到next方法里。這個(gè)方法里需要一個(gè)具體的業(yè)務(wù)邏輯,例如寫(xiě)文件,屏幕打印日志,追加到DOM里,不管怎么說(shuō)需要你來(lái)完成的。

訂閱

只要訂閱一個(gè)Observable對(duì)象就會(huì)返回一個(gè)訂閱對(duì)象,另外當(dāng)完成后你可以使用unsubscribe方法釋放掉對(duì)象流。這種釋放機(jī)制真的很優(yōu)美,它解決了原生JS在事件處理完成后正確釋放資源的缺點(diǎn)。原生JS在這一塊之前總是會(huì)出問(wèn)題。

為了說(shuō)明這一點(diǎn),我創(chuàng)建一個(gè)Observable對(duì)象來(lái)監(jiān)聽(tīng)所有的點(diǎn)擊事件:

很明顯這是一個(gè)無(wú)限觸發(fā)的點(diǎn)擊事件流(事件完成方法永遠(yuǎn)不會(huì)調(diào)用)。如果我要停止監(jiān)聽(tīng)事件,我只需要簡(jiǎn)單的調(diào)用unsubscribe方法。這個(gè)方法也會(huì)清理和釋放事件的句柄資源或者臨時(shí)對(duì)象資源。

現(xiàn)在你知道了如何創(chuàng)建和銷毀事件流,那么再看看怎么使用它來(lái)解決具體的問(wèn)題吧。在我的模型里采用數(shù)字來(lái)說(shuō)明這些API的使用,當(dāng)然你可以把他們應(yīng)用到任何的業(yè)務(wù)邏輯。

流式序列化

RxJS框架的核心思想是提供一個(gè)統(tǒng)一的數(shù)據(jù)處理的編程模型,不考慮數(shù)據(jù)類型,以及是否同步異步(遠(yuǎn)程HTTP調(diào)用)等因素。RxJS使用簡(jiǎn)單又熟悉的API。通過(guò)函數(shù)式方法擴(kuò)展了原生JavaScript的數(shù)組集合(被認(rèn)為是擴(kuò)展的組數(shù)),這些方法是map,filter和reduce等。

? ? ? ? ? ? ? ? 方法
? ? ? ? ? ? ? ? 說(shuō)明
? ? ? ? ? ? ? ? map(fn)? ? ? ? ? ? ? ? 重新構(gòu)建observable序列對(duì)象為新的形式
? ? ? ? ? ? ? ? filter(predicate)? ? ? ? ? ? ? ? 通過(guò)給定的predicate函數(shù),過(guò)濾掉匹配的observable序列對(duì)象
? ? ? ? ? ? ? ? reduce(accumulator, [seed])? ? ? ? ? ? ? ? 通過(guò)收集器函數(shù)accumulator返回一個(gè)單一結(jié)果。seed是收集器的初始化數(shù)據(jù)。

使用從數(shù)字1到5的數(shù)組,我將要過(guò)濾掉奇數(shù),計(jì)算它們的平方和總和。按照傳統(tǒng)的方式至少會(huì)使用到循環(huán)和條件判斷。使用函數(shù)式方法就會(huì)這樣:

其實(shí)這是很小的改變,就是通過(guò)Observable對(duì)象實(shí)例方法來(lái)進(jìn)行數(shù)據(jù)處理。就像數(shù)組一樣,被處理的對(duì)象來(lái)自于前一個(gè)方法的返回結(jié)果。目的在當(dāng)前輸入對(duì)象的范疇內(nèi)執(zhí)行特定的操作方法(map,filter,reduce),處理所需的業(yè)務(wù)邏輯。

下面的圖展示了這個(gè)場(chǎng)景下的執(zhí)行過(guò)程:

數(shù)組是一種可預(yù)測(cè)的流,因?yàn)閳?zhí)行期間所用數(shù)據(jù)都放在內(nèi)存中。無(wú)論數(shù)據(jù)是以怎樣的形式,假如這些數(shù)據(jù)是通過(guò)HTTP請(qǐng)求方式獲得后被執(zhí)行(或者封裝成Promise對(duì)象),同樣的代碼仍然有效:

當(dāng)然,我可以創(chuàng)建獨(dú)立的無(wú)副作用的函數(shù),并注入到可觀測(cè)的序列中。這可以讓你的代碼看起來(lái)更直觀:

這是RxJS的美麗之處:單個(gè)編程模型可以支持所有的情況。此外,可觀測(cè)能讓你序列化你的串行操作,使它們?cè)谝黄疬\(yùn)作良好,并讓抽象化延遲遠(yuǎn)離你的代碼。還需要注意的是,這種寫(xiě)代碼的方式消除了循環(huán)和條件語(yǔ)句的復(fù)雜性,這是一種更高層的函數(shù)。

處理時(shí)間

了解RxJS 如何有效處理時(shí)間以及通過(guò)基于時(shí)間的延遲可以做運(yùn)算符。這里有一個(gè)簡(jiǎn)短的列表用于隨著時(shí)間推移創(chuàng)建最常見(jiàn)的狀態(tài):

名稱描述
Rx.Observable.interval(period)在每一個(gè)時(shí)期返回一個(gè)可觀測(cè)序列產(chǎn)生值
Rx.Observable.timer(dueTime)在dueTime運(yùn)行后產(chǎn)生一個(gè)值,然后在每一個(gè)時(shí)期返回一個(gè)可觀測(cè)序列

這些都是很好的模擬時(shí)間事件:

每半秒鐘間隔(500)將排放值。因?yàn)檫@是一個(gè)無(wú)限流,我只有前5個(gè),將可觀測(cè)到一個(gè)有限的流,發(fā)送完成一個(gè)信號(hào)。

處理用戶輸入

你也可以使用Observable對(duì)象與DOM事件進(jìn)行交互。使用Rx.Observable.fromEvent,我能監(jiān)聽(tīng)到任何DOM事件信息。這有一個(gè)小例子:

在這個(gè)事例中,我可以處理點(diǎn)擊事件,并能夠在觀察者(Observer)里執(zhí)行任何操作。這里的map方法是轉(zhuǎn)換接收到的點(diǎn)擊事件,從點(diǎn)擊事件里提取底層元素的href屬性。

處理異步調(diào)用

處理用戶輸入不只是異步調(diào)用的唯一方式。RxJS框架也優(yōu)雅地整合了ES6 Promise API,這樣就可以獲取遠(yuǎn)程數(shù)據(jù)。假如要從Github上獲取用戶并且提取用戶名。RxJS框架的強(qiáng)大,讓我們處理這些邏輯只用5行代碼就夠了。

這段代碼引入了一對(duì)新方法,這里要解釋一下。首先我把Github的用戶列表REST API包裝成Observable對(duì)象。在flatMap方法里通過(guò)makeHttpCall函數(shù)來(lái)對(duì)URL地址進(jìn)行請(qǐng)求,去獲得一個(gè)Promise化的AJAX返回對(duì)象。這時(shí)RxJS要等待返回結(jié)果以及Promise化處理。一旦完成,Github的響應(yīng)數(shù)據(jù)就會(huì)在函數(shù)里被包裝成數(shù)組存放進(jìn)Observable對(duì)象里。接下來(lái)就是調(diào)用Observable對(duì)象的方法來(lái)處理數(shù)據(jù)。最后我構(gòu)造了一個(gè)簡(jiǎn)單的函數(shù)來(lái)從數(shù)組集合里提取用戶名屬性。

Map與FlatMap對(duì)比

正如前面所說(shuō),Observable對(duì)象的map方法是對(duì)自身對(duì)象的數(shù)據(jù)值進(jìn)行映射處理,返回是一個(gè)包含映射結(jié)果的新Observale對(duì)象。調(diào)用的方法能返回任意類型對(duì)象,甚至另外的Observable類型對(duì)象。上面的例子是我把帶有URL信息的lambda表達(dá)式作為參數(shù)輸入,返回結(jié)果是把promise類型對(duì)象又包裝成Observalbe對(duì)象輸出:

映射方法把Observalbe對(duì)象里數(shù)據(jù)結(jié)果進(jìn)行映射產(chǎn)生一個(gè)新Observable對(duì)象。(在函數(shù)式編程里這種方式很普遍)我們要做的就是處理映射關(guān)系并把結(jié)果存放到一個(gè)Observalbe對(duì)象里,這有點(diǎn)像給洋蔥剝皮。這正是flatMap方法的優(yōu)點(diǎn)。上面的方法返回結(jié)果是Rx.Observable.fromPromise(...),所以需要處理promise對(duì)象。從一般經(jīng)驗(yàn)來(lái)看,當(dāng)你從其他類型對(duì)象中構(gòu)建Observalbe對(duì)象時(shí),需要使用flatMap方法。下面看一個(gè)例子就好理解了:

這段代碼是以0.5秒間隔生成5個(gè)連續(xù)數(shù)字的界面。首先輸出數(shù)字1到5,然后2到6,3到7等等。如下圖所示:

釋放可觀察序列

前面提到了,RxJS框架的好處之一是對(duì)JavaScript事件進(jìn)行了統(tǒng)一抽象,這樣可以更好的釋放和銷毀事件。這就是基于觀察者(Observer)里提供了這個(gè)功能去執(zhí)行自己的清理方法。訂閱Observable對(duì)象就會(huì)獲得一個(gè)Subscription實(shí)例,通過(guò)這個(gè)實(shí)例就能得到觀察者(Observer)對(duì)象實(shí)例。

這段代碼創(chuàng)建一個(gè)簡(jiǎn)單的Observable對(duì)象。但這次不是對(duì)事件數(shù)據(jù)源或AJAX數(shù)據(jù)源進(jìn)行包裝,而是創(chuàng)建一個(gè)自定義的事件,會(huì)不間斷的每隔一秒產(chǎn)生數(shù)字。因?yàn)槭亲远x事件所以需要通過(guò)訂閱返回的函數(shù)調(diào)用來(lái)創(chuàng)建自己的資源釋放程序。RxJS框架通過(guò)Subscription.unsubcribe()的調(diào)用執(zhí)行去釋放資源。這個(gè)例子中我的清理動(dòng)作只是時(shí)間間隔函數(shù)。7秒之后,我釋放了Observable對(duì)象所以引起輸出數(shù)字暫停而不是無(wú)限制的打印數(shù)字。

合并流

你似乎認(rèn)為這些Observalbe對(duì)象很重,實(shí)際上他們創(chuàng)建和釋放是很容易的。就像變量一樣,它們可以被合并在一起。下面看看如何進(jìn)行合并操作。

合并多個(gè)流

merge方法負(fù)責(zé)執(zhí)行合并操作,合成多個(gè)Observalble序列變成一個(gè)Observalble對(duì)象。這個(gè)操作方法就是把多個(gè)事件流合并成一個(gè),在時(shí)間的維度里順序一致。例如在一個(gè)HTML組件里有三個(gè)按鈕,分別執(zhí)行以下方式進(jìn)行計(jì)數(shù):上,下和清除。

另一種流的合并方式是可以通過(guò)concat()和concatAll()方法進(jìn)行。

一個(gè)流與另一個(gè)合并

withLatestFrom 這個(gè)操作者是非常有用的,因?yàn)樗试S您將一個(gè)observable序列合并到另一個(gè)正在使用選擇器方法的序列中,除非原始的observable序列產(chǎn)生一個(gè)元素。為了展示這一點(diǎn),假設(shè)我想在每一秒鐘打印出GitHub的用戶列表。直觀上,我需要將一個(gè)基于時(shí)間的流與一個(gè)HTTP的流合并。

緩存

正如更早之前提到的,流是一種無(wú)狀態(tài)的數(shù)據(jù)結(jié)構(gòu),這就意味著其狀態(tài)從未滯留其中而是立即從生產(chǎn)者流向消費(fèi)者。然而有時(shí)重要的是它能夠臨時(shí)存儲(chǔ)一些數(shù)據(jù),并且還可以再次基礎(chǔ)上做出決定。想到的一個(gè)例子是關(guān)于跟蹤雙擊一個(gè)元素。你是如何在不存儲(chǔ)第一次點(diǎn)擊的情況下監(jiān)測(cè)到第二次點(diǎn)擊?為此,我們可以使用緩存。有多種情況:

緩沖一段時(shí)間

你可以暫時(shí)保存一定數(shù)量的數(shù)據(jù)到內(nèi)部數(shù)組,一旦滿足計(jì)數(shù)閾值時(shí),它將作為一個(gè)整體得到釋放.

?

1 2 3 4 5 Rx.Observable.range(1,?9)?.bufferCount(3) .subscribe(console.log); //->?prints?[1,?2,?3] //??????[4,?5,?6] //??????[7,?8,?9]

基于時(shí)間的緩沖數(shù)據(jù)

你也可以為一個(gè)預(yù)定義的時(shí)間緩沖. ?我將創(chuàng)建一個(gè)簡(jiǎn)單的函數(shù)來(lái)模擬每秒鐘從一組可用的郵箱地址發(fā)送郵件來(lái)顯示. 如果我每秒鐘發(fā)一封郵件, 和緩沖, 說(shuō), 五秒鐘,一旦緩沖時(shí)間運(yùn)行緩沖將發(fā)出一組郵件:

錯(cuò)誤處理

上面的例子中,我們已經(jīng)學(xué)習(xí)了在處理DOM事件或者獲取遠(yuǎn)程數(shù)據(jù)時(shí),幾種關(guān)于 streams (流)?的異步操作方式。但是,這些例子里面并沒(méi)有告訴我們,如果處理 stream 的過(guò)程中出現(xiàn)了錯(cuò)誤或者異常,我們應(yīng)該怎樣處理。DOM事件handler里面比較簡(jiǎn)單,因?yàn)樗麄儗?shí)際上不拋出錯(cuò)誤。但是AJAX不在此列。如果你不是處理簡(jiǎn)單的數(shù)組,那么 stream 有很大的不可預(yù)測(cè)性,你必須考慮到會(huì)有錯(cuò)誤或者異常發(fā)生。

對(duì)于錯(cuò)誤,如果你傳遞了自己的 observer(觀察器),你需要在內(nèi)部使用try...catch 并調(diào)用 observer.onError(error)。這將允許你捕捉和處理相關(guān)錯(cuò)誤,并最終 dispose。

當(dāng)然,你也可以使用 .onErrorResumeNext。


捕捉異常(Catch )

所幸你可以像以前一樣使用 catch 語(yǔ)句 (現(xiàn)在是一個(gè)操作符 operator) 。為了演示,我將在stream到達(dá)值5的時(shí)候手動(dòng)創(chuàng)建一個(gè)錯(cuò)誤。

當(dāng)條件滿足時(shí),異常將被拋出并一路傳播到 stream 事先注冊(cè)的 Observer。你可能想優(yōu)雅地捕獲異常并顯示一個(gè)比較友好的消息。

catch操作符允許你處理指定的錯(cuò)誤并防止該錯(cuò)誤傳播到其他已注冊(cè)的下游observer。這個(gè)操作符可以搭配另一個(gè)?Observable 將相應(yīng)的錯(cuò)誤傳遞出去,所以你可以通過(guò)這個(gè)方式在出錯(cuò)時(shí)建議某些默認(rèn)值。注意:此時(shí)關(guān)聯(lián)到那個(gè) observer 的錯(cuò)誤處理函數(shù)將不會(huì)被觸發(fā)。

現(xiàn)在,如果我們想要標(biāo)記一個(gè)不可恢復(fù)的情況,你可以?catch?且 throw?錯(cuò)誤。在?catch 塊內(nèi),這段代碼將會(huì)導(dǎo)致異常解除。我注意到,其拋出異常時(shí)的其副作用將會(huì)波及其他期待處理的地方。在真正關(guān)鍵的部分這應(yīng)該少用。

另一個(gè)選擇是嘗試重試。

重試

在可監(jiān)控的范圍內(nèi),你可以重試上一行操作確定的次數(shù),之前的失敗將會(huì)被解除。

最后,作為JavaScript 開(kāi)發(fā)者,我們整天都跟事件或者異步計(jì)算打交道。我們?cè)趯?shí)現(xiàn)復(fù)雜UI或者復(fù)雜狀態(tài)機(jī)時(shí),為了保證在失敗時(shí)能夠保持響應(yīng),這些代碼將變得越來(lái)越復(fù)雜。RxJS 真正實(shí)現(xiàn)了?Reactive Manifesto?的兩個(gè)最重要的基本原則,也就是Responsive (響應(yīng)式)?和?Resilient(自適應(yīng)性).

此外,RxJS 將這些計(jì)算指令提升為語(yǔ)言的第一等級(jí)特性,由此組成了JavaScript里面最先進(jìn)的事件處理系統(tǒng)。這一切組成了一個(gè)統(tǒng)一的計(jì)算模型來(lái)處理這些異步計(jì)算指令。該模型包含了可讀性高,易于組合的API,并剝離了一些零碎的細(xì)節(jié)(如延遲和等待時(shí)間等)。

更多參考資料

  • http://rxmarbles.com/

  • http://reactivex.io/

  • http://callbackhell.com/

  • http://xgrommx.github.io/rx-book/

  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

  • https://gist.github.com/staltz/868e7e9bc2a7b8c1f754

  • https://github.com/Reactive-Extensions/RxJS/tree/master/doc/designguidelines

原文地址:http://www.oschina.net/translate/rxjs-streams


.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺(tái)或掃描二維碼關(guān)注

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)

總結(jié)

以上是生活随笔為你收集整理的使用 RxJS 实现 JavaScript 的 Reactive 编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 91成人精品一区在线播放 | 国产一区二区三区日韩 | 成人两性视频 | 精品少妇一区二区三区免费观看 | 亚洲福利一区二区 | 国产欧美精品一区二区色综合朱莉 | 精品国偷自产在线 | av直播在线观看 | 亚洲资源站 | 鲁丝一区二区三区 | 亚洲性欧美 | 久久女人 | 久草免费在线观看视频 | 黄网站在线播放 | 成人视屏在线 | 日韩激情床戏 | 午夜一区在线观看 | 四虎影院在线看 | 国产精品婷婷 | 黑丝av在线 | 亚洲福利 | 欧美韩国日本在线 | av大片免费观看 | 亚洲一区二区在线播放 | 第四色影音先锋 | 特种兵之深入敌后高清全集免费观看 | 在线观看高清视频 | 中文字幕一区二区三区在线不卡 | 亚洲成人基地 | 777奇米四色 | 丁香av| 在线视频网| 国产精品区一区二区三 | 日韩一级片免费 | 久久激情视频 | 伊人久久大香线蕉av一区 | 日本精品专区 | 99国产精品久久久久99打野战 | 九九热精品免费视频 | 国产亚洲精品久久久久久青梅 | 日韩理论片在线观看 | 好吊视频一区二区 | 国产精品推荐 | 一区二区三区精 | 国产盗摄视频在线观看 | 91成人在线| 色片网站在线观看 | 九一网站在线观看 | 日韩三级在线观看 | 久久亚洲无码视频 | 金鱼妻日剧免费观看完整版全集 | 国产精品又黄又爽又色无遮挡 | 久久久一 | 蜜桃臀aⅴ精品一区二区三区 | 国产亚洲性欧美日韩在线观看软件 | 美女被变态侵犯 | 97人妻精品一区二区三区 | 国产精品一区二区精品 | 夜间福利视频 | 91天堂网| 波多野结衣免费视频观看 | 日韩啪| 精品亚洲永久免费精品 | 91精品国产高清一区二区三蜜臀 | 久久久香蕉网 | 香蕉久久精品日日躁夜夜躁 | 爽爽影院在线 | 毛片免费全部无码播放 | 亚洲天堂一区二区 | 中文字幕人妻一区二区三区视频 | 久久久精品999| av大片网址 | 九九热视 | 欧美一级久久久 | 龚玥菲三级露全乳视频 | 激情av在线| 免费av入口 | 国产亚洲制服欧洲高清一区 | 色哟哟国产精品 | 欧美精品成人一区二区三区四区 | 高清在线一区二区三区 | 日本不卡一区视频 | 亚洲成人福利在线 | 国产高清一区在线观看 | 日韩一页| av动漫网站 | 狠狠干夜夜草 | av合集| 男人爱看的网站 | 国产日韩欧美一区二区东京热 | 成人观看网站 | 亚洲午夜久久久久久久久 | 成人激情av | 水果派解说av | 2017天天干| 国产综合久久久久久鬼色 | 在线观看免费毛片 | 日本伦理在线 | 东方av在线免费观看 |