RxJS學習之路七(手寫Subject和簡單應用)

爲何使用Subject

Subject和observable同樣能夠被訂閱,可是它們在被屢次訂閱的時候表現是不同的。vue

observable在被屢次訂閱時,每一次的訂閱都是獨立的,也是重頭開始的訂閱,訂閱之間不會相互干涉。以下所示git

const test = interval(1000);

test.subscribe(res => console.log(res))
setTimeout(() => {
  test.subscribe(res => console.log(res))
}, 1000);

// 0
// 1
// 0
// 2
// 1
// 3
// 2
....
複製代碼

可是在實際狀況中,有的時候咱們不但願他們是獨立的,在不少須要共享觸發的狀況下,咱們會但願他們在訂閱的時候,不會從頭返回,而是全部訂閱都返回相同的觸發,而這個就是Subject的做用。github

手寫一個Subject

理解一個東西最好的辦法就是手寫一個,Subject的實現能夠理解爲用一箇中介來獲取全部observers,而後在觸發時同時執行。vuex

const subject = {
    observers: [],
    subscribe: function(observer) {
        this.observers.push(observer)
    },
    next: function(value) {
        this.observers.forEach(o => o.next(value))    
    },
    error: function(error){
        this.observers.forEach(o => o.error(error))
    },
    complete: function() {
        this.observers.forEach(o => o.complete())
    }
}

const c = interval(1000);
test.subscribe(subject.subscribe(res => cosnole.log('a:' + res)))
setTimeout(() => {
  test.subscribe(subject.subscribe(res => cosnole.log('b:' + res)))
}, 1000);

// a:0
// a:1
// b:1
// a:2
// b:2
// a:3
// b:3
// a:4
...
複製代碼

Subject的應用

手寫的這個Subject和實際的實現有一些小差異,不過將Subject的關鍵點都覆蓋到了。 Subject具備兩個特色:bash

  • Subject能夠被訂閱是一個observable,同時它包含了各類observer,因此它同時是observable和observer
  • Subject會對內部包含的全部observer同時觸發

依據這兩個特性,Subject常常被用在一些須要主動觸發的場合,還有一些不一樣組件之間共享變化的狀況。學習

例如一個網頁有一個國際化需求,能夠設置多種語言類型,在選擇了語言類型以後,全部模塊的語言都會發生變化,若是項目很大組件繁多,用簡單的組件間通信就會很是麻煩,熟悉vue的同窗通常會用vuex來解決這種問題,而Rxjs就能夠很簡單的作到。在咱們只須要公共的服務中new一個Subject對象,在設置語言變化的時候觸發Subject.next(language),而後在須要的作出改變的模塊中監聽這個Subject的變化輸出便可。以angular代碼爲例:ui

// common service 
  languageChange$ = new Subject();
  
  changeLanguage(language){
    setLang(language);
    this.languageChange$.next(language);
  } 
複製代碼
// other components
constructor(
    private _srv: CommonService
 ) {
    this._srv.languageChange$.subscribe(language => {
        this.setLanguage(language)
    })
 }
  
  setLanguage() {
    ...
  }
複製代碼

這種須要實現一處變化多處相應的狀況,Subject是一把利器。this

有一個經常使用到的需求,在一個組件,經常會有多個observable存在監聽各類事件的發生,在關閉這個組件時,咱們須要中止掉全部的observable,這個也能夠用Subject來統一監聽,統一關閉。以angular代碼爲例:spa

private _unsubscribe$ = new Subject<void>();
  
  someObservable.pipe(
    takeUntil(this._unsubscribe$),
    someOperators...
  ).subscribe(callback)
  
  ngOnDestroy() {
    this._unsubscribe$.next();
    this._unsubscribe$.complete();
  }
複製代碼

github上有一個項目封裝了一個流程管理的庫,用的就是rxjs裏的subject。code

ng流程管理庫tinystate

有興趣的能夠去學習這個庫的源碼實現,相信對RxJs的理解提升有很大幫助.

相關文章
相關標籤/搜索