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