什么是Rxjs
RxJS是使用Observables 的響應(yīng)式編程的庫(kù),它使編寫(xiě)異步或基于回調(diào)的代碼更容易。隨著深入你會(huì)發(fā)現(xiàn)它采用了訂閱者模式,其中也帶有純函數(shù)的思想,比如Rxjs5中我們把“副作用”都寫(xiě)在.do()中。直到在使用了RxJS 6之后才了解其少有人意識(shí)到的另一面——流。
什么是流?node中的stream,gulp中的管道流... 這里我們不用專(zhuān)業(yè)術(shù)語(yǔ)來(lái)解釋?zhuān)蒙钪写蠹沂煜さ牡睦觼?lái)類(lèi)比,比如“河流”。
河流有什么特點(diǎn)?至少有兩個(gè)特點(diǎn):水往低處流,河流雖然可能會(huì)蜿蜒盤(pán)旋,但是朝向固定,比如我國(guó)的長(zhǎng)江和黃河就都是由西向東流。在RxJS中數(shù)據(jù)的流向也是固定的,就是從發(fā)送者到訂閱者。基本都如下面這種形式:
河道有無(wú)數(shù)的分支也有無(wú)數(shù)的合并,在Rxjs中的是,通過(guò)不同的操作符將數(shù)據(jù)流拆分處理聚合又拆分。RxJS 6 相對(duì)于 RxJS 5(這里指5.5以下的版本,因?yàn)?a href="http://ttokpm.com/tags/pi/" target="_blank">pipe函數(shù)在RxJS 5.5中作為新特性已被引入) 來(lái)說(shuō)不僅修改了一部分操作符的名稱,同時(shí)做了一個(gè)較大的改動(dòng),引入了管道(pipe)。
這種寫(xiě)法上的變化就帶來(lái)了用法上的變化,以前的固定“河流”可以通過(guò)“管道”(pipe)來(lái)控制形成靈活的“水流”。
Rxjs vs Promise
Rxjs 和傳統(tǒng)的Promise在處理異步問(wèn)題上有什么差距呢?再代碼層面什么是Rxjs說(shuō)到底是要理解什么是Observable。RXJS是Observable的Javascript實(shí)現(xiàn)。
promise相較于Rxjs而言功能更單一 promise 只能將一個(gè)數(shù)據(jù)的狀態(tài)由pending轉(zhuǎn)換成resoloved或者rejected.而Rxjs可以處理多個(gè)數(shù)據(jù)對(duì)應(yīng)complete和error狀態(tài)但是Rxjs同時(shí)又擁有next方法。Observable是惰性的,需要subscribe的時(shí)候才輸出值。promise內(nèi)部狀態(tài)是不可控制的,執(zhí)行了就無(wú)法終止。而Observable可以定義如何取消異步方法。這也就是我下面會(huì)討論到的一個(gè)異步場(chǎng)景。
輸入框中輸入字符,按回車(chē)發(fā)送一個(gè)請(qǐng)求,并將返回的結(jié)果變成一個(gè)todo item。如果在請(qǐng)求返回結(jié)果前又一次按下回車(chē)或add按鈕,如果相同則不進(jìn)行任何操作,如果不同則取消掉上次的請(qǐng)求并發(fā)送新的請(qǐng)求。(實(shí)際的場(chǎng)景往往是發(fā)送個(gè)http請(qǐng)求該請(qǐng)求會(huì)返回的很慢,業(yè)務(wù)上加上心跳檢查,如果前一次在心跳間隔內(nèi)無(wú)返回則再次調(diào)用請(qǐng)求,同時(shí)需要拋棄前一次請(qǐng)求的返回,并且此時(shí)有可能調(diào)用參數(shù)不一樣的該接口從而造成數(shù)據(jù)不一致的問(wèn)題)對(duì)于Promise實(shí)現(xiàn)我們不只要維護(hù)一個(gè)定時(shí)器timer 同時(shí)還要維護(hù)一個(gè)全局變量。
而Rxjs 我們可以通過(guò)switchMap 切換 Observable達(dá)到該效果
為什么使用 switchMap?
switchMap和其他打平操作符的主要區(qū)別是它具有取消效果。在每次發(fā)出時(shí),會(huì)取消前一個(gè)內(nèi)部 observable (你所提供函數(shù)的結(jié)果) 的訂閱,然后訂閱一個(gè)新的observable 。你可以通過(guò)短語(yǔ)切換成一個(gè)新的 observable來(lái)記憶它。
它能在像 typeaheads 這樣的場(chǎng)景下完美使用,當(dāng)有新的輸入時(shí)便不再關(guān)心之前請(qǐng)求的響應(yīng)結(jié)果。在內(nèi)部observable長(zhǎng)期存活可能會(huì)導(dǎo)致內(nèi)存泄露的情況下,這也是一種安全的選擇,例如,如果你使用mergeMap和interval,并忘記正確處理內(nèi)部訂閱。記住,switchMap 同一時(shí)間只維護(hù)一個(gè)內(nèi)部訂閱,在示例1中可以清楚出看到這一點(diǎn)。
不過(guò)要小心,在每個(gè)請(qǐng)求都需要完成的情況下,考慮寫(xiě)數(shù)據(jù)庫(kù),你可能要避免使用 switchMap。如果源observable發(fā)出速度足夠快的話,switchMap可以取消請(qǐng)求。在這些場(chǎng)景中,mergeMap是正確的選擇。
這里的switchMap其實(shí)是map and switch,而switch操作符的行為是:
如果Observable中流動(dòng)的數(shù)據(jù)也是Observable,switch會(huì)將數(shù)據(jù)流中最新的一個(gè) Observable訂閱并將它的值傳遞給下一個(gè)操作符,然后取消訂閱之前的 Observable。
簡(jiǎn)直就是為心跳檢查量身定做。不管你異步的狀態(tài)是怎么樣switchMap中的Observable只訂閱最新的一個(gè)。下面有個(gè)例子可以幫你很清晰的理解:
嘗試一些場(chǎng)景中使用Rxjs
1.寫(xiě)一個(gè)基于 websocket 的在線聊天室,每次websocket收到新消息,不可能都立刻渲染出來(lái),如果是用于生產(chǎn),同時(shí)會(huì)有很多人說(shuō)話wx渲染很大程度會(huì)有性能問(wèn)題。用JS寫(xiě)的話,你需要維護(hù)一個(gè)數(shù)組,和一個(gè)timer,收到消息,先放進(jìn)數(shù)組,然后timer負(fù)責(zé)把消息渲染出來(lái),同時(shí)還要考慮清理timer,類(lèi)似:
而在Rxjs中通過(guò)操作符bufferTime 就可以減少維護(hù)timer的成本:
比如我們需要監(jiān)聽(tīng)頁(yè)面滾動(dòng)的事件,作出一些邏輯操作,這是就會(huì)產(chǎn)生事件過(guò)于頻繁的調(diào)用,造成頁(yè)面卡頓的現(xiàn)象。用原生js實(shí)現(xiàn)的時(shí)候,需要實(shí)現(xiàn)個(gè)節(jié)流或者防抖函數(shù),通過(guò)實(shí)現(xiàn)個(gè)閉包函數(shù),在內(nèi)部維護(hù)個(gè)定時(shí)器。而在Rxjs中通過(guò)操作符debounce 就可以方便的解決
評(píng)論
查看更多