30 天精通 RxJS (07): Observable Operators & Marble Diagrams

Observable 的 Operators 是實例應用上最重要的部份,咱們須要瞭解各類 Operators 的使用方式,才能輕鬆實現各類需求!javascript

這是【30天精通 RxJS】的 07 篇,若是還沒看過 06 篇能夠往這邊走:
30 天精通 RxJS (06): 創建 Observable(二)%EF%BC%9A%20%E5%BB%BA%E7%AB%8B%20Observable(%E4%BA%8C).md)java

昨天咱們把全部創建 Observable 實例的 operators 講完了,接下來咱們要講關於轉換(Transformation)、過濾(Filter)、合併(Combination)等操做方法。先來讓咱們看看什麼是 Operatorgit

什麼是 Operator?

Operators 就是一個個被附加到 Observable 型別的函數,例如像是 map, filter, contactAll... 等等,全部這些函數都會拿到本來的 observable 並回傳一個新的 observable,就像有點像下面這個樣子github

var people = Rx.Observable.of('Jerry', 'Anna');

function map(source, callback) {
    return Rx.Observable.create((observer) => {
        return source.subscribe(
            (value) => { 
                try{
                    observer.next(callback(value));
                } catch(e) {
                    observer.error(e);
                }
            },
            (err) => { observer.error(err); },
            () => { observer.complete() }
        )
    })
}

var helloPeople = map(people, (item) => item + ' Hello~');

helloPeople.subscribe(console.log);
// Jerry Hello~
// Anna Hello~複製代碼

JSBin | JSFiddle數組

這裏能夠看到咱們寫了一個 map 的函數,它接收了兩個參數,第一個是本來的 observable,第二個是 map 的 callback function。map 內部第一件事就是用 create 創建一個新的 observable 並回傳,而且在內部訂閱本來的 observable。函數

固然咱們也能夠直接把 map 塞到 Observable.prototype學習

function map(callback) {
    return Rx.Observable.create((observer) => {
        return this.subscribe(
            (value) => { 
                try{
                    observer.next(callback(value));
                } catch(e) {
                    observer.error(e);
                }
            },
            (err) => { observer.error(err); },
            () => { observer.complete() }
        )
    })
}
Rx.Observable.prototype.map = map;
var people = Rx.Observable.of('Jerry', 'Anna');
var helloPeople = people.map((item) => item + ' Hello~');

helloPeople.subscribe(console.log);
// Jerry Hello~
// Anna Hello~複製代碼

這裏有兩個重點是咱們必定要知道的,每一個 operator 都會回傳一個新的 observable,而咱們能夠透過 create 的方法創建各類 operator。ui

在 RxJS 5 的實例中,其實每一個 operator 是透過原來 observable 的 lift 方法來創建新的 observable,這個方法會在新回傳的 observable 事件內偷塞兩個屬性,分別是 source(來源) 與 operator,記錄本來的資料源跟當前使用的 operator。this

其實 lift 方法仍是用 new Observable(跟 create 同樣)。至於爲何要獨立出這個方法,除了更好的封裝之外,主要的緣由是爲了讓 RxJS 5 的使用者能更好的 debug。關於 RxJS 5 的除錯方式,咱們會專門寫一篇來說解!spa

這裏咱們只是簡單的實例 operator。若是以後實例上,想要不影響本來的 Observable 又可以自訂 operator 能夠參考官方的這份文件。(如今先不用看)

其實 RxJS 提供的各類 operators 已經很是夠用了,不太須要咱們本身創造 operator,這裏只是想讓你們先對 operator 的創建有個基本的觀念,以後在學習的過程當中會比較輕鬆。

在咱們開始介紹 RxJS 的 operators 前,爲了能讓咱們更好地理解各類 operators,咱們須要先訂定一個簡單的方式來表達 observable!

Marble diagrams

咱們在傳達事物時,文字實際上是最糟的手段,雖然文字是咱們平時溝通的基礎,但經常千言萬語也比不過一張清楚的圖。若是咱們能訂定 observable 的圖示,就能讓咱們更方便的溝通及理解 observable 的各類 operators!

咱們把描繪 observable 的圖示稱爲 Marble diagrams,在網路上 RxJS 有很是多的 Marble diagrams,規則大體上都是相同的,這裏爲了方便撰寫以及跟讀者的留言互動,因此採用相似 ASCII 的繪畫方式。

咱們用 - 來表達一小段時間,這些 - 串起就表明一個 observable。

----------------複製代碼

X (大寫 X)則表明有錯誤發生

---------------X複製代碼

| 則表明 observable 結束

----------------|複製代碼

在這個時間序當中,咱們可能會發發送值(value),若是值是數字則直接用阿拉伯數字取代,其餘的資料型別則用相近的英文符號表明,這裏咱們用 interval 舉例

var source = Rx.Observable.interval(1000);複製代碼

source 的圖形就會長像這樣

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

當 observable 是同步送值的時候,例如

var source = Rx.Observable.of(1,2,3,4);複製代碼

source 的圖形就會長像這樣

(1234)|複製代碼

小括號表明着同步發生。

另外的 Marble diagrams 也可以表達 operator 的先後轉換,例如

var source = Rx.Observable.interval(1000);
var newest = source.map(x => x + 1);複製代碼

這時 Marble diagrams 就會長像這樣

source: -----0-----1-----2-----3--...
            map(x => x + 1)
newest: -----1-----2-----3-----4--...複製代碼

最上面是本來的 observable,中間是 operator,下面則是新的 observable。

以上就是 Marble diagrams 如何表示 operator 對 observable 的操做,這能讓咱們更好的理解各個 operator。

Marble Diagrams 相關資源:rxmarbles.com/

最後讓咱們來看幾個簡單的 Operators!

Operators

map

Observable 的 map 方法使用上跟數組的 map 是同樣的,咱們傳入一個 callback function,這個 callback function 會帶入每次發發送來的元素,而後咱們回傳新的元素,以下

var source = Rx.Observable.interval(1000);
var newest = source.map(x => x + 1); 

newest.subscribe(console.log);
// 1
// 2
// 3
// 4
// 5..複製代碼

用 Marble diagrams 表達就是

source: -----0-----1-----2-----3--...
            map(x => x + 1)
newest: -----1-----2-----3-----4--...複製代碼

咱們有另一個方法跟 map 很像,叫 mapTo

mapTo

mapTo 能夠把傳進來的值改爲一個固定的值,以下

var source = Rx.Observable.interval(1000);
var newest = source.mapTo(2); 

newest.subscribe(console.log);
// 2
// 2
// 2
// 2..複製代碼

mapTo 用 Marble diagrams 表達

source: -----0-----1-----2-----3--...
                mapTo(2)
newest: -----2-----2-----2-----2--...複製代碼

filter

filter 在使用上也跟數組的相同,咱們要傳入一個 callback function,這個 function 會傳入每一個被髮送的元素,而且回傳一個 boolean 值,若是爲 true 的話就會保留,若是爲 false 就會被濾掉,以下

var source = Rx.Observable.interval(1000);
var newest = source.filter(x => x % 2 === 0); 

newest.subscribe(console.log);
// 0
// 2
// 4
// 6..複製代碼

filter 用 Marble diagrams 表達

source: -----0-----1-----2-----3-----4-...
            filter(x => x % 2 === 0)
newest: -----0-----------2-----------4-...複製代碼

讀者應該有發現 map, filter 這些方法其實都跟數組的相同,由於這些都是 functional programming 的通用函數,就算換個語言也有機會看到相同的命名及相同的用法。

實際上 Observable 跟 Array 的 operators(map, filter),在行爲上仍是有極大的差別。當咱們的資料量很大時,Observable 的效能會好上很是多。咱們會有一天專門講這個部份!

今日小結

今天咱們講了 Observable Operators 的相關知識,有如下幾個重點

  • 什麼是 Operators
    • 如何創建 operator
  • Marble diagrams
  • Operators
    • map
    • mapTo
    • filter

不知道今天讀者有沒有收穫呢?歡迎在下方留言給我,這是精通 RxJS 的第 07 篇!

相關文章
相關標籤/搜索