rxjs擁有大量的操做符能夠說基本涵括平常使用的方方面面, 但總有一天會有沒有符合要求的操做符的一天, 或者, 即便有, 但咱們卻沒有找到, 畢竟已經存在的操做符已經不少了, 說不定會愈來愈多, 這時就須要咱們來自定義操做符了。html
本文針對 rxjs6 ,之前的版本能夠查看 這篇文章。
在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
接下來讓咱們用一個簡單的例子來實現如下函數式編程
假如咱們須要一個對數字進行平方的操做符:函數
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())));
自定義操做符除了能夠經過pipe()
進行,還有不少地方提到了lift()
這個方法, 而且不少地方都把 lift()
和pipe()
做爲對比,因此又去學習了一下lift()
idea
建立一個新的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
rxjs
中lift()
如何使用呢, ,下面是一個簡單的例子,改造後的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?