【Rxjs】 - 解析四种主题Subject
原文地址:?https://segmentfault.com/a/1190000012669794
? ? ? ?
引言
開發ngx(angular 2+)應用時,基本上到處都會用到rxjs來處理異步請求,事件調用等等。所以經常會使用Subject來處理源源不斷的數據流,比如input text change, toast notification等等。
這都要依賴于Subject本身既可以是Observable也可以是Observer,也就是說subject既可以作為一個數據源,也可以本身成為一組訂閱者的代理。
但當處理更加復雜的業務需求時,僅僅用Subject可能無法滿足要求,這個時候就考慮一下rxjs提供的其他Subject Class了, 例如BehaviorSubject?ReplaySubject?AsyncSubject, 接下來我們就來看一下他們跟Subject有什么區別,各自有什么特點,在什么時候更適合使用。
[文中代碼均使用typescript]
Subject
首先我們來創建一個Rxjs Subject, 數據的類型是number
let?subject1: Subject<number> =?new?Subject<number>();?// (A)然后我們使用Subject的next方法來emit(發射)1條數據
subject1.next(100); (B)接下來對subject1創建兩個訂閱,在subscription中直接打印接受到的數據
subject1.subscribe((res: number) => console.info("subjectA ", res)); // (C) subject1.subscribe((res: number) => console.info("subjectB ", res));接下來我在發射兩條數據
subject1.next(200); (D)subject1.next(300); 好了,接下來我們就來看看console里面會打印出什么結果。
也許有的同學會覺得結果是這樣的,因為Subject可以接收源源不斷的數據嘛,所以無論發射多少次數據,訂閱者都能接收到。
這個結果不太對
因為Subject的訂閱者只有在訂閱后,才能接收到數據源發射過來的值。
所以在代碼塊C中, 訂閱者在訂閱數據源subject1之前, 無論代碼塊B執行多少次, 訂閱者也只能收到代碼C之后發射的數據。
正確的結果應該是:
//output subjectA 200 subjectB 200 subjectA 300 subjectB 300 這種情況在項目里經常能遇到,有時候我明明從數據源發射一個數據,但在訂閱者拿到的值卻是undefined或者null, 這就是因為訂閱者是在數據源發射之后創建的,自然無法接收到數據了。
假如我們想在訂閱者創建之后,無論什么時候都能拿到數據, 這應該怎么辦呢? 那就要考慮使用BehaviourSubject了。
BehaviorSubject
我們依舊使用剛才的例子, 創建一個BehaviorSubject, 默認值設為0.?BehaviorSubject需要給個默認值
然后發射一條數據100,創建一個訂閱者,再發射一條數據200,再創建一個訂閱者,最后發射一條數據300。
代碼如下:
這個時候結果就應該是:
//output behavior-subjectA 100 behavior-subjectA 200 behavior-subjectB 200 behavior-subjectA 300 behavior-subjectB 300 由于BehaviorSubject是可以存儲最后一條數據或者初始默認值的, 所以無論訂閱者什么時候訂閱到數據源subject2上, 都能接收到數據。
所以針對訂閱者behavior-subjectA, 他訂閱的時候,數據流里最后一條數據是100, 他能立即接收到。 然后依次能接收到最新的數據200和300。
針對訂閱者behavior-subjectB, 他訂閱的時候,數據流里最后一條數據是200, 他能立即接收到。 然后只能能接收到最新的數據300了。
BehaviorSubject給予我們的便利就是,無論何時訂閱到數據源,始終都能拿到最新的或者初始的數據,但也只能拿到一條數據,但當我們處理input text change事件時,需要拿到用戶輸入的所有字符,也就是數據流的所有數據,BehaviorSubject就無能為力了,這個時候我們考慮使用ReplaySubject了。
ReplaySubject
我們依舊使用剛才的例子, 創建一個ReplaySubject, 發射兩條數據100和200,創建一個訂閱者,再發射一條數據300,再創建一個訂閱者,最后發射一條數據400。
代碼如下:
控制打印的結果將是:
//output replay-subjectA 100 replay-subjectA 200 replay-subjectA 300 replay-subjectB 100 replay-subjectB 200 replay-subjectB 300 replay-subjectA 400 replay-subjectB 400 ReplaySubject會存儲數據流中的所有數據,無論何時訂閱到subject3,訂閱者都能獲取了訂閱之前數據流里的所有數據,然后依舊獲取到接下來獲取的到的新數據。
就像ReplaySubject類名的中Replay, 一旦訂閱到數據源,就會將數據流像放電影一樣重新放一遍給你。
訂閱者replay-subjectA訂閱到subject3的時候,數據流里已經有了100和200, 接收并打印出來。
最后打印新數據300和400.
訂閱者replay-subjectB訂閱到subject3的時候,數據流里已經有了100,200,300, 接收并打印出來。最后打印新數據400.
接下來就要說下最后一種Subject了,也就是AsyncSubject
AsyncSubject
AsyncSubject和BehaviorSubject`ReplaySubject`有些類似,但不同的是AsyncSubject只會存儲數據流里的最后一條數據, 而且只有在數據流complete時才會將值發布出去。
AsyncSubject主要是用來處理異步操作,當數據源是異步請求或者事件處理時,可能會發射出很多數據,如果我們只希望數據源的異步操作完成的時候,訂閱者才能接收到值,這個時候就可以使用AsyncSubject了。
接下來我們看個例子,
創建一個AsyncSubject, 然后發射數據,創建訂閱者,再發射數據。。。
最后的結果就應該是:
//output4 async-subjectA 400 async-subjectB 400 async-subjectC 400 async-subjectD 400 由于subject4是AsyncSubject, 只有在complete的時候才會向訂閱者publish數據,而且只publish最后一次數據,所以無論訂閱者何時訂閱數據源,都可以接收到最后一次數據。
但為什么沒有打印出500呢,因為數據源已經complete了,你就無法再發射新數據了。
總結
最后來總結一下四種Subject的特點,理解好的各自的特點,在項目開發中可以處理很多棘手的需求,同時也會避免很多問題的發生。
轉載于:https://www.cnblogs.com/lnlvinso/p/11228724.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的【Rxjs】 - 解析四种主题Subject的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GPRS底层API(转)
- 下一篇: 再谈borland与MS对BUG的不同态