爲rxjs添加自定義操做符

rxjs擁有大量的操做符能夠說基本涵括平常使用的方方面面, 但總有一天會有沒有符合要求的操做符的一天, 或者, 即便有, 但咱們卻沒有找到, 畢竟已經存在的操做符已經不少了, 說不定會愈來愈多, 這時就須要咱們來自定義操做符了。html

本文針對 rxjs6 ,之前的版本能夠查看 這篇文章

爲Operator添加操做符

在5.5版本, rxjs增長了pipe操做符, 在那以後, 自定義操做符的方式就很簡單了, 基本就是實現一個函數, 官方文檔中有以下描述:編程

基本上來講,pipeable 操做符能夠是任何函數,可是它須要返回簽名爲 <T, R>(source: Observable<T>) => Observable<R>的函數。
如今 Observable中有一個內置的 pipe方法 ( Observable.prototype.pipe),它能夠用相似於以前的鏈式調用的方式來組合操做符

因此咱們只須要定義一個函數, 他的返回值簽名是<T, R>(source: Observable<T>) => Observable<R>就能夠了。segmentfault

在使用一個例子開始之前,讓咱們看看編寫操做符的注意事項ide

  • 操做符的返回值必須是Observable類型,沒有第二種可能。
  • 必定要管理好subscription,這樣訂閱生產的資源才能及時被釋放。
  • 處理好異常,由於你沒法保證用戶傳進來的邏輯永遠均可以正確運行。
  • 在合適的時間,處理好其它你須要釋放的資源,例如流結時,或拋出錯誤時。

接下來讓咱們用一個簡單的例子來實現如下函數式編程

一個簡單的例子

假如咱們須要一個對數字進行平方的操做符:函數

square = () => {
    return source => {
      return source.pipe(map((value: number) => value * value));
    };
  }

他的入參爲空, 返回的函數的行參source就是即將被傳入的observable,
而後咱們就能夠在,pipe()中調用了學習

test() {
    const obs = of(1, 2, 3);
    // 1, 4, 9
    obs.pipe(square()).subscribe((value) => console.log(value)); 
  }

一個簡單的操做符就完成了,但,是否是感受還少了些什麼,對,要是傳入進來的不是一個數字呢,那時用戶會收到一個NaN(Not a Number), 因此,咱們還須要給他判斷一下並報錯ui

const square = () => source => source
  .pipe(map((value: number) => {
        // 判斷傳入的值是否爲數字
      if (value && !isNaN(value)) {
        return value * value;
      }
      throw Error('收到的數據不是數值類型');
    }),
    catchError(err => of(err.toString())));

lift()

自定義操做符除了能夠經過pipe()進行,還有不少地方提到了lift()這個方法, 而且不少地方都把 lift()pipe()做爲對比,因此又去學習了一下lift()
image.pngidea

建立一個新的Observable,以該Observable做爲源,並將傳遞的運算符定義爲新Observable的運算符。

它和pipe()的對比能夠查看這篇文章
簡單的說spa

lift()建立一個新的可觀察對象,但pipe()沒有。pipe()遵循函數式編程範式,lift()是面向對象的。

(後面這部分感受理解的還不是很到位就不翻譯了)

  • pipe's operator function maps an Observable to an Observable
  • lift's operator function maps an Observer to an Observer

This is just another way to represent the idea of either:

  • building an Observable chain down from the source to the sink
  • or building an Observer chain up from the sink to the source

如何使用lift()

rxjslift()如何使用呢, ,下面是一個簡單的例子,改造後的square():

class Square implements Operator<number, number> {
  call(subscriber: Subscriber<number>, source: Observable<number>): void {
    source.subscribe(value => {
        if (value && !isNaN(value)) {
          subscriber.next(value * value);
        }
        throw Error('收到的數據不是數值類型');
      },
      error => console.log(error));
  }
}

使用

test() {
    const obs = of(123);
    obs.lift(new Square()).subscribe((value) => console.log(value)); // 1, 4, 9
  }

上面只是一個簡單的例子,若想經過lift()編寫操做符,能夠直接參考那些操做符的源碼, lift()在源碼中有大量的使用。

總結

寫完之後能明顯的感受到這篇文章還有很大的改進空間,原本還想更細緻探討一下原理性的東西的,可是那一大堆花裏胡哨的函數簽名看的本身直髮暈,並且如今彙報時間就要到了,仍是算了,等本身水平再提高一些了再來看吧。

參考文章

Rxjs-自定義操做符
官方文檔
What is the difference between Observable.lift and Observable.pipe in rxjs?

相關文章
相關標籤/搜索