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すれば、条件分岐は達成できます。