rxjs之operator使用介紹

14 mins.
  1. 1. operator
    1. 1.1. of
    2. 1.2. from
    3. 1.3. fromEvent
    4. 1.4. map
    5. 1.5. mergeMap
    6. 1.6. switchMap
    7. 1.7. concatMap
    8. 1.8. filter
    9. 1.9. tap
    10. 1.10. takeUntil
    11. 1.11. toArray
    12. 1.12. reduce
    13. 1.13. catchError
    14. 1.14. debounceTime
    15. 1.15. delay
    16. 1.16. bufferCount
    17. 1.17. pairwise
    18. 1.18. bufferTime
    19. 1.19. 小結
  2. 2. subject
  3. 3. 結論

很多人在使用rx的時候,往往遇到的瓶頸是operator的使用,因為實在太多可以使用,今天要來分享一下我曾經用過以及常用的operator是哪些

operator

從一開始寫Rx到現在,全部使用的operator有差不多18個左右,其中只有五個是最常用的,其他都是遇到需求而使用

目前官方大概有100個左右

of

將參數輸出成資料流,常用建構observable之一

1
2
3
4
of(1, 2, 3).subscribe(console.log);
// 1
// 2
// 3

from

of類似,個人蠻常用在將陣列拆解

1
2
3
4
from([1, 2, 3]).subscribe(console.log);
// 1
// 2
// 3

fromEvent

監聽element的事件最佳利器!!沒有之一XD

1
fromEvent(window, 'scroll').subscribe(console.log);

map

這個是最常用之一,只要有任何的物件轉換就一定會使用到,而且一段裡面可能會使用好幾次

1
2
3
4
5
map(p => ({
id: p.id,
name: p.Name,
})
)

mergeMap

把merge和map的功能合一,兩個observable資料是可以並行進來輸出

switchMap

功能與mergeMap類似,資料進來後會取消前面的資料重新要一次

concatMap

mergeMap類似,但會等到前一個observable結束才會執行,通常使用於前面的API結束後才能執行後面的API

filter

顧名思義,就是過濾資料用,例如重複的資料不想要,或是只想要拿到某些資料

1
2
3
from([true, false, true]).pipe(
filter(p => !!p)
)

tap

基本上寫rx應該要讓每一個function都是pure的,減少side effect
但如果真的再中間需要寫入一些值的話就可以使用,另一個使用狀況就是debug啦

1
2
3
4
from([true, false, true]).pipe(
filter(p => !!p),
tap(console.log),
)

takeUntil

比較多使用在unsubscribe一個observable,在angular中就是ngOnDestroy事件中,在react就是componentWillUnmount

1
2
3
4
5
6
7
8
9
10
fromEvent(window, 'scroll').pipe(
takeUntil(this.destory$)
)

destory$ = new Subject();

ngOneDestory(){
this.destory$.next();
this.destory$.complete();
}

toArray

前面有說到會用switchMap把陣列拆解開,但最後的資料就是需要陣列,這時候就很適合使用

1
2
3
of(1, 2, 3).pipe(
toArray()
)

reduce

資料整理上的好幫手,可以把陣列拆解,然後可以輸出任何類型的資料

1
2
3
4
5
from([1, 2, 3]).pipe(
reduce((acc, value) => {
acc.push(value * 2);
}, [])
)

catchError

我主要應用在串接API,當發生錯誤時要先做處理然後再讓呼叫端拿到error

1
2
3
4
5
6
7
8
of(undefined).pipe(
map(p => p.name),
catchError(p => {
// do something
// 結束整個observable
return Observable.throw(p);
})
)

debounceTime

收到資料沒有變化多久的時間後就會觸發,適合在不想要被頻繁觸發的事件上,例如autocomplete

1
2
3
fromEvent(input, 'keyDown').pipe(
debounceTime(200)
)

delay

跟sleep差不多的概念(笑),基本上只使用過一次,demo project為了模擬api的效果才用的

bufferCount

累積n筆資料以後才輸出,輸出為陣列,但要注意,如果數量不夠,那些資料就會一直卡在拿不到!基本上也只使用過一次

1
2
3
of(1, 2, 3).pipe(
bufferCount(2)
)

pairwise

情境是為了要可以拿到連續配對的資料 [1, 2] [2, 3] [3, 4];只使用過一次

補充,也能用在scroll事件,可以用來判斷前次和這次的捲軸位置

1
2
3
of(1, 2, 3).pipe(
pairwise()
)

bufferTime

資料需要被累積一定時間後再一起輸出,輸出為陣列;只使用過一次

1
2
3
of(1, 2, 3).pipe(
bufferTime(100),
)

小結

好的,介紹完曾經使用過的operator,有沒有發現有不少都非常的難用到,因為情境太少,畢竟大部分的情況都還是在整理資料或是串接的用途

subject

為什麼要額外提subject呢,因為這個功能實在太好用啦,使用情境來列一下

  • 變數值是一樣的,但希望被重複觸發

    例如alert message,什麼時候不會管,外層只需要呼叫讓component顯示就好

1
2
3
4
5
6
7
//只會觸發一次
var openDialog = true;
//<app-dialog [open]="openDialog" />

var openDialog$ = new Subject();
openDialog$.next(true);
//<app-dialog [open]="openDialog$" />
  • 手動控制資料時間點,例如destory
  • 需要有預設值或是取得前幾次的結果(其他subject)

結論

operator常用的就那幾個,剩下都是屬於情境型的應用,再沒有看到那種case的情況下,就是不知道這些要怎麼使用,所以也不用擔心,先開始用並且寫下去就知道
我也寫過一個map露露等5.60行的,先交差,後面再來想要怎麼改善,一次到位永遠都是最痛苦的

看完這篇也能看看另一篇 Rx真實案例展示 會更有感覺喔!

如果覺得挑戰不夠,可以看看這個repo,絕對給你滿滿的應用!