これだけ知ってれば大丈夫(かもしれない)RxJS5の厳選オペレータ

  • 27
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

RxJS5のオペレータはだいぶ削減されたようですが、それでも100近くあります。
なのでRx歴3日の私がこれだけ知ってれば大丈夫かも?と思ったオペレータを(三日坊主を避けるために)つらつら並べます。理解が相当怪しいと思うので、突っ込み大歓迎です、むしろお願いします。

Reactive Programmingの荒い説明

例えば、ボタンが押されたら、入力した文字をWebAPIを叩いて検索して、結果を表示する、という処理を考えます。
すべてが同期的に行えるとしたら、以下のようになります。


function main(){
  if(button.click){
    let inputText = inputTextBox.text;
    let result = query(iniputText);
    outputTextBox.text = result;
  }
}

このうち、参照された変数が変更された場合(この場合だと、button.click、inputTextBox.text)、自動的にロジックの再計算を走らせたらどうでしょう?というのが基本的な考え方です。

これはつまり、変数に変更に対して反応するコードです。Reactive ProgrammingのReactiveとは、これを指します。

RxJS

JavaScriptはReactive Programming Languageではありませんので、この考え方をJavaScript界に具象化する必要があります。そのためのライブラリがRxJSになります。

何かに対して何かを行う、をつなげて、そこにメッセージを流し込む、というモデルです。

Observable

何に対して反応するか、その「何」にあたるのがObservableになります。

Operator

何をおこなうのか、その「何」に当たるのがOperatorです。

subscribe

Operatorの端点です。これが呼ばれないとなにも起きません。

厳選オペレータ

いきなりですが構造化プログラミングの基本です。
GOTO地獄から脱出するために必要なパーツは三つです。

  • 順次
  • 反復
  • 分岐

これをRxJSにおいてどう実現するか、そして、そのオペレータが基本的なOperatorであるとみなして並べます。

順次

流れてきたメッセージに対して処理を行います。

map

流れてきたメッセージに対して、変更を加えて、次に渡します。

do

メッセージが流れてきた、をトリガにして、処理を実行します。
主に副作用を担当します。

switchMap,concatMap,flatMap

switchMapは、流れてきたメッセージをObservableに変換する関数を受け取り、それに置き換えます。
concatMapは直列に、flatMapは並列に繋ぎます。
順次実行の文脈では、主な使い道としては非同期処理です。


text$
  .switchMap((t)=>query(t))
  .subscribe((t)=>console.log(t));

switchMapはPromiseを受け取ると、resolveされたらその値が流れるObservableに変換してくれます。
よって、もしquery()がPromiseを返す非同期処理ならば、

textにデータが流れて来たら、queryを実行、そして結果をコンソールに出力して、終了する。

という流れになります。

反復

そもそもObservableという概念が、反復を内包しています。よって、配列等、反復対象になるデータをObservableに変換する処理があればOK、ということになります。

concatMap

流れてきたメッセージをメッセージの流れに変換して、それを直列につなぎます。


array$
  .concatMap((ts)=>Rx.Observable.from(ts))
  .subsribe((t)=>console.log(t));

switchMap

また出てきましたが、例えば配列の終了通知が必要な場合は、こちらになります。

flatMap

こちらは並列なので、反復内容に非同期処理が混ざって、各々を止めたくない場合に使用します。


array$
  .switchMap((ts)=>Rx.Observable.of(ts))
  .flatMap(t=>query(t))
  .subsribe((t)=>console.log(t));

分岐

メッセージの分配と、その条件が必要になります。

share

流れてくるメッセージを分配します。注意したいのは、RxJSでは、以下は分配になりません。


let source$ = text$.do((v)=>doIt(v));
source$.subsribe((v)=>console.log(v));
source$.subsribe((v)=>console.log(v));

意図に反して、textにメッセージが流れるたび、doItが二回呼ばれます。
この挙動を理解するためにはHotとColdの概念を理解する必要があります。
また、参照透過なOperatorのみの場合上でもうまくいく等、無意味に複雑です。
最初のうちは、分配したい場合はshare、でよいと思います。

filter

条件を満たした場合、値を通過します。
分配した後、各々でfilterすれば、条件分岐は達成できます。