學習 RXJS 系列(一)——從幾個設計模式開始聊起

一、RXJS 是什麼

RXJS 是 Reactive Extensions for JavaScript 的縮寫,起源於 Reactive Extensions,是一個基於可觀測數據流 Stream 結合觀察者模式和迭代器模式的一種異步編程的應用庫。RxJS 是 Reactive Extensions 在 JavaScript 上的實現。

二、前置知識

響應式編程

響應式編程(Reactive Programming)是一種基於事件的模型,它是一種面向數據流和變化傳播的編程範式。這意味着可以在編程語言中很方便地表達靜態或動態的數據流,而相關的計算模型會自動將變化的值通過數據流進行傳播。例如,對於 a=b+c 這個表達式的處理,在命令式編程中,會先計算 b+c 的結果,再把此結果賦值給 變量 a,因此 b,c 兩值的變化不會對 變量 a 產生影響。但在響應式編程中,變量 a 的值會隨時跟隨 b,c 的變化而變化。

響應式編程的思路大概如下:你可以用包括 Click 和 Hover 事件在內的任何東西創建 Data stream。任何東西都可以是一個 Stream:變量、用戶輸入、屬性、Cache、數據結構等等。

概括來說,流的本質是一個按時間順序排列的進行中事件的序列集合。我們可以對一個或多個流進行過濾、轉換等操作。需要注意的是,流是不可改變的,所以對流進行操作後會在原來的基礎上返回一個新的流。

觀察者模式

觀察者模式(有時又被稱爲模型(Model)- 視圖(View)模式、源 - 收聽者 (Listener) 模式或從屬者模式)是軟件設計模式的一種。在此種模式中,一個目標物件管理所有相依於它的觀察者物件,並且在它本身的狀態改變時主動發出通知。這通常透過呼叫各觀察者所提供的方法來實現。此種模式通常被用來實現事件處理系統。

觀察者模式(Observer)完美的將觀察者和被觀察的對象分離開。舉個例子,用戶界面可以作爲一個觀察者,業務數據是被觀察者,用戶界面觀察業務數據的變化,發現數據變化後,就顯示在界面上。看到上面這個描述的場景是不是覺得似曾相識?Vue 的工作原理不就是這樣的嗎,將數據與視圖雙向綁定,通過響應式編程的思想動態更新訂閱的觀察者列表。

迭代器模式

迭代器模式(Iterator Pattern)是一種非常常用的設計模式。這種模式用於順序訪問集合對象的元素,不需要知道集合對象的底層表示。迭代器模式屬於行爲型模式。

JavaScript 中 原有表示 “集合” 的數據結構主要是 “數組 (Array)” 和 “對象 (Object)”,ES6 又新增了 Map 和 Set,共四種數據集合,瀏覽器端還有 NodeList 類數組結構。ES6 中也有 Iterator 迭代器的介紹,爲 “集合” 型數據尋求統一的遍歷接口正是 ES6 的 Iterator 誕生的背景。

三、基本概念介紹

Observable

Observable 表示一個可調用的未來值或事件的集合,他能被多個 observer 訂閱,每個訂閱關係相互獨立、互不影響。這裏可以舉個簡單的例子,假如你訂閱了報紙,只要報紙每次有新的內容出來就會送到(更新)你手上,這個場景中報紙就是 Observable,而你就是一個觀察者(observer)。

我們看看在 RXJS 中怎麼創建一個 Observable:

const Rx = require('rxjs/Rx');

const newObservable = Rx.Observable.create(observer => {
  observer.next('message1');
});

這裏通過調用 Observable.create 創建了一個 Observable,這個方法接受一個函數作爲參數,這個函數叫做 producer 函數, 用來生成 Observable 的值。這個函數的入參是 observer,在函數內部通過調用 observer.next() 便可生成有一系列值的一個 Observable

Observer

Observer 是一個回調函數的集合,也就是一個包含幾個回調函數的對象。它知道如何去監聽由 Observable 提供的值。Observer 在信號流中是一個觀察者(哨兵)的角色,它負責觀察任務執行的狀態並向流中發射信號。

我們簡單描述下一個 Observer 長什麼樣子:

const observer = {
    next: function(value) {
        console.log(value);
    },
    error: function(error) {
        console.log(error);
    },
    complete: function() {
        console.log('complete');
    }
}

RXJS 中 Observer 的回調函數是可選的,我們定義 Observer 時可以不定義 next、error 或者 complete,這並不會對 Observer 的執行造成影響。

我們來看下如何定義一個 Observer:

const newObservable = Rx.Observable.create((observer) => {
    observer.next('message1');
})

newObservable.subscribe((text) =>console.log(text));

這裏通過 subscribe 方法讓一個 observer 訂閱一個 Observable。你可能對 subscribe 的參數有些疑惑,這裏我們可以看看 subscribe 的函數定義,瞭解是如何與上面我們提到的 next、error 和 complete 關聯起來的:

subscribe(next?: (value: T) =>void, error?: (error: any) =>void, complete?: () =>void): Subscription;

從入參來看,從左至右依次是 nexterrorcomplete,並且是可選的,我們可以自己選擇性的傳入相關回調,因爲他們都是可選的。

Subscription

Subscription 表示 Observable 的執行,我們可以調用該對象的 unsubscribe 方法清理掉 Observable 的執行,這個方法不需要任何參數,只是用來清理由 Subscription 佔用的資源。

const myObservable = Rx.Observable.create(observer => {
  observer.next('foo');
  setTimeout(() => observer.next('bar'), 1000);
});
const subscription = myObservable.subscribe(x =>console.log(x));

subscription.unsubscribe();

我們可以看到,Observable 的執行需要調用 subscribe 方法來觸發,如果在 Observable 執行的時候我們調用了 unsubscribe 方法,就會取消正在進行中的 Observable 的執行。

Subject

Subject 對象可以當成是一箇中間代理,它位於 Observable 和 Observer 中間,相對於 Observable 來說它是一個 Observer,接收 Observable 發出的數據;相對於 Observer 它又是一個 Observable,對訂閱了它的 observer 發送數據。

需要注意的是,Subject 會對訂閱了它的 observers 進行多播,這裏就涉及到一個單播與多播的概念了,我們分析一下這兩個概念:

單播:單播的意思是,每個普通的 Observables 實例都只能被一個觀察者訂閱,當它被其他觀察者訂閱的時候會產生一個新的實例。也就是普通 Observables 被不同的觀察者訂閱的時候,會有多個實例,不管觀察者是從何時開始訂閱,每個實例都是從頭開始把值發給對應的觀察者。

多播:前面說到,每個普通的 Observables 實例都只能被一個觀察者訂閱,但是如果通過 Subject 來代理 Observable 實例的話就能夠被多個 observer 所訂閱,且無論有沒有 observer 訂閱,都會發送數據。也就是說無論 observer 什麼時候訂閱都只會接收到實時的數據。

四、參考文章

  1. RxJS—— 給你如絲一般順滑的編程體驗

  2. RXJS 中文文檔

下一篇文章中我們繼續介紹一下幾種不同類型的 Subject 以及 Cold/Hot Observables,希望能對大家有所幫助。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/tlFb4NHcdr5Ej8kxzfO88w