初識RxJS

玉鴦發表於2017-08-08

什麼是Rx.JS?

  Rx.JS是英文 Reactive Extensions for JavaScript 的縮寫.翻譯成中文就是:JavaScript的響應式擴充套件.其主要的功能就是利用響應式程式設計的模式來實現JavaScript的非同步式程式設計.
  相對於JavaScript中其它的非同步式解決方式(回撥函式、Promise、Gender、async函式而言),Rx.JS有著更加強大的特性和更加優雅的寫法.如(純淨性、流動性、值)。

Rx.JS的基本概念

  Rx.JS的響應式程式設計操作是結合了觀察者模式、迭代模式以及函數語言程式設計來實現的.它主要有著如下幾個概念:

  • Observable (可觀察物件): 表示一個概念,這個概念是一個可呼叫的未來值或事件的集合。
  • Observer (觀察者): 一個回撥函式的集合,它知道如何去監聽由 Observable 提供的值。
  • Subscription (訂閱): 表示 Observable 的執行,主要用於取消 Observable 的執行。
  • Operators (操作符): 採用函數語言程式設計風格的純函式 (pure function),使用像 map、filter、concat、flatMap 等這樣的操作符來處理集合。
  • Subject (主體): 相當於 EventEmitter,並且是將值或事件多路推送給多個 Observer 的唯一方式。
  • Schedulers (排程器): 用來控制併發並且是中央集權的排程員,允許我們在發生計算時進行協調,例如 setTimeout 或 requestAnimationFrame 或其他。

  下面,來讓我們看一個簡單的示例.
  我們都知道,在前端開發當中為效能的優化,我們往往會對某個持續不斷會觸發的事件做一下事件節流.,也就是事件增加一個節流閥,以限制事件的不斷觸發.最常見的做法就是設定一個定時器.來進行判斷.事件在多少秒之內不斷觸發的話.就將節流閥開啟.不進行事件操作.直達不斷觸發事件的行為結束之後,才進行事件操作.最常見的就是輸入框的例子.如下面程式碼所示:

<input id="text"></input>
<script>
    var text = document.querySelector('#text'),
        timer = null,
        currentSearch = '';

    text.addEventListener('keyup', (e) =>{
        clearTimeout(timer)
        timer = setTimeout(() => {
            // 宣告一個當前所搜的狀態變數
            currentSearch = '書';

            var searchText = e.target.value;
            $.ajax({
                url: `search.qq.com/${searchText}`,
                success: data => {
                    // 判斷後臺返回的標誌與我們存的當前搜尋變數是否一致
                    if (data.search === currentSearch) {
                        // 渲染展示
                        render(data);
                    } else {
                        // ..
                    }
                }
            });
        },250)
    })
</script>複製程式碼

  上面的程式碼就是一個很常見的一個事件節流的用法.當你按下鍵盤觸發事件時,並不是直接傳送AJAX請求.而是使用setTimeout延遲250毫秒.在延遲的過程中如果有新的事件觸發.就會重新計算延遲.如此不斷的反覆.直到兩次觸發事件的間隔大於250毫秒.才會真正的傳送AJAX請求.

  下面讓我們來看看上述的邏輯用RxJS怎樣的實現.

var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
  .debounceTime(250)
  .subscribe(function(){
      $.ajax({
        url: `search.qq.com/${searchText}`,
        success: data => {
          // 判斷後臺返回的標誌與我們存的當前搜尋變數是否一致
          if (data.search === currentSearch) {
            // 渲染展示
            render(data);
          } else {
            // ..
          }
        }
    });
  });複製程式碼

  上面是用RxJS實現的同樣的功能.但我們看到其程式碼精簡了許多.上述程式碼中首先獲取到一個button元素.然後使用Rx.Observable.fromEvent建立了一個被觀察物件.其物件所監聽的是button元素的.click事件.每當button元素的click事件觸發時.就會發射一個值出去.這個值途中經過debounceTime操作符,延時了250毫秒.然後再被觀察者物件捕獲.最終觸發其定義的AJAX事件.這就是上述程式碼中的實現過程.
  然而我們看到.雖然上述在定義執行的過程中做了許多的事情,但這些是RxJS在內部幫助我們就做好了的.我們只需要它給我們的API方法就可以實現用幾段簡單的程式碼,實現一段複雜的操作.

Observable (可觀察物件)

Observables 是多個值的惰性推送集合

  Observable是RxJS的核心概念之一.它實際上就是可以被外界觀察的一個物件.當本身的狀態發生變化時,就會將其變化推送給外界觀察它的物件,也就是 觀察者物件.同時因為Observables 是多個值的惰性推送集合所以只有當使用一個觀察者物件去訂閱了它之後.它才會同步或非同步地返回零到(有可能的)無限多個值.下面是使用RxJS建立一個Observable的方式

var observable = Rx.Observable.create(function subscribe(observer) {
  var id = setInterval(() => {
    observer.next('hi')
  }, 1000);
});複製程式碼

上面例項建立了一個 Observable,它每隔一秒會向觀察者傳送字串 'hi'.

Observer (觀察者)

什麼是觀察者? - 觀察者是由 Observable 傳送的值的消費者。觀察者只是一組回撥函式的集合,每個回撥函式對應一種 Observable 傳送的通知型別:next、error 和 complete 。

  簡單來說,Observer就是使用Observable傳送出來值的一個方法集合.當一個Observable傳送出來值之後由Observer來決定如何的去使用它.而使用的方式就是通過回撥函式.將Observable傳送出來的值作為引數傳入其中.讓後在內部去使用.同時根據Observable傳送出來的值不同.其呼叫的回撥函式也不同.分別有next(下一步),error(報錯),complete(結束).下面是使用Observer的方法:

observable.subscribe(observer);複製程式碼

要使用觀察者,需要把它提供給 Observable 的 subscribe 方法

Subscription (訂閱)

什麼是 Subscription ? - Subscription 是表示可清理資源的物件,通常是 Observable 的執行。Subscription 有一個重要的方法,即 unsubscribe,它不需要任何引數,只是用來清理由 Subscription 佔用的資源。在上一個版本的 RxJS 中,Subscription 叫做 "Disposable" (可清理物件)。

  Subscription(訂閱)是使用observable.subscribe()建立一個觀察者物件時.所返回的一個物件.它主要就是使用unsubscribe() 函式主動關閉ObserverObservable的監聽訂閱.其使用方法如下:

var observable = Rx.Observable.interval(1000);
var subscription = observable.subscribe(x => console.log(x));
// 稍後:
// 這會取消正在進行中的 Observable 執行
// Observable 執行是通過使用觀察者呼叫 subscribe 方法啟動的
subscription.unsubscribe();複製程式碼

Operators (操作符)

操作符是 Observable 型別上的方法,比如 .map(...)、.filter(...)、.merge(...),等等。當操作符被呼叫時,它們不會改變已經存在的 Observable 例項。相反,它們返回一個新的 Observable ,它的 subscription 邏輯基於第一個 Observable 。

操作符是函式,它基於當前的 Observable 建立一個新的 Observable。這是一個無副作用的操作:前面的 Observable 保持不變。

  就本質上而言Operators就是一個純粹的函式.它可以接收一個 Observable 作為輸入.並在經過內部的一系列處理後返回一個新的Observable作為輸出.流向下一個操作.

Subject (主體)

什麼是 Subject? - RxJS Subject 是一種特殊型別的 Observable,它允許將值多播給多個觀察者,所以 Subject 是多播的,而普通的 Observables 是單播的(每個已訂閱的觀察者都擁有 Observable 的獨立執行)。

Subject 像是 Observalbe,但是可以多播給多個觀察者。Subject 還像是 EventEmitters,維護著多個監聽器的登錄檔。

  每一個Subject都同時是一個ObservableObserver.對於Subject你可以使用subscribe方法並指定一個觀察者.也可以呼叫next(v)error(e)complete()來處理接受道到值.示例如下:


var subject = new Rx.Subject();

subject.subscribe({
  next: (v) => console.log('observerA: ' + v)
});
subject.subscribe({
  next: (v) => console.log('observerB: ' + v)
});

subject.next(1);
subject.next(2);複製程式碼

在上面的示例中,我們為 Subject 新增了兩個觀察者,然後給 Subject 提供一些值

Schedulers (排程器)

什麼是排程器? - 排程器控制著何時啟動 subscription 和何時傳送通知。它由三部分組成:

  • 排程器是一種資料結構。 它知道如何根據優先順序或其他標準來儲存任務和將任務進行排序。
  • 排程器是執行上下文。 它表示在何時何地執行任務(舉例來說,立即的,或另一種回撥函式機制(比如 setTimeout 或 process.nextTick),或動畫幀)。
  • 排程器有一個(虛擬的)時鐘。 排程器功能通過它的 getter 方法 now() 提供了“時間”的概念。在具體排程器上安排的任務將嚴格遵循該時鐘所表示的時間。

排程器可以讓你規定 Observable 在什麼樣的執行上下文中傳送通知給它的觀察者。

上面是我最近學習RxJS時一些粗淺的總結,希望對大家有所幫助.如果文中有何不當之處請予以斧正,資訊.

參考資料

我的個人網址: www.wangyiming19950222.com