switchmapとは
switchMapとはoperatorの一つです。
ただし挙動が特殊です。しかも日本語の資料がほとんどインターネット上にないのでわかる範囲で挙動をまとめてみました。
ちなみに私の場合はAngularのプロジェクト内でRxJSを使っています。
※素人が書いているので間違っているところがあれば指摘していただけると助かります
動かしてみる
switchMapを一言でいうと受け取ったObservableが持っている値を下流に流すoperatorです。
とりあえず今回書いたコードを以下に転記します。
<input type="button" value="rxjs" id="rxjsSample">
ngAfterViewInit() {
let element = document.getElementById('rxjsSample');
// クリックイベント時に1を流すObservableを作成する
let click$ = fromEvent(element, 'click').pipe(
mapTo(1)
);
// click$が流した値をコンソールに吐いた後、流れてきた値を3倍にするObservableを作成する
click$.pipe(
switchMap(
value => this.innerObservable(value)
)
).subscribe(value => console.log(`subscribe: ${value}`))
}
innerObservable(value) {
console.log(value);
return of(value * 3);
}
実行結果
ボタンをクリックするたびに1、subscribe: 3
がコンソールに出力されます。
Angularを勉強したことがない方向けに説明するとngAfterViewInit
はwindow.onload
のようなもので、画面読み込み時に実行される関数だと思ってください。
switchMapはoparatorなので、当然pipeメソッド内で使用します。
とりあえずお作法としてswitchMapの引数には関数オブジェクト
を渡します。また、関数オブジェクトの戻り値はObservable
でなければいけません。
今回でいうとswitchMapにはvalue =>this.innerObservable(value)
という関数オブジェクトを渡していて、of
で作成されたObservableが関数から返されます。
ここでswitchMapはボタンクリック時にmapTo(1)
により流れてきた1を受け取り、innerObservable
を実行しています。innerObservable
では受け取った値(ここでは1)をコンソールに出力して3
(正確には1 * 3)を流すObservableを返しています。
switchMapはof(3)を受け取り、of(3)が流す値(つまり3)を下流に流します。
つまりここではclick$
が流した1
をもとに新しいObservableを作成することで値を作成しています。(ここ重要)
もう一つの特徴
さっきの例ではクリックしたらすぐに3が流れますが、もしof(3)
ではなくinterval(1000)
のような何秒も値を流し続けるObservableを使った場合、注意するべき挙動があります。
<input type="button" value="rxjs" id="rxjsSample">
ngAfterViewInit() {
let element = document.getElementById('rxjsSample');
// クリックイベント時に1を流すObservableを作成する
let click$ = fromEvent(element, 'click').pipe(
mapTo(1)
);
click$.pipe(
switchMap(value => {
return interval(1000).pipe(take(5))
})
).subscribe(value => console.log(value));
}
結果
of(3)の代わりにinterval(1000).pipe(take(5))
を使用しているので一回クリックすると0, 1, 2, 3, 4が1秒おきに流れます。
値が流れている途中にもう一度クリックを押すと1回目にクリックに対応する値は流れなくなり、2回目のクリックに対応する値のみが流れます。
つまり、新しい値が流れてくると内部Observableによる値の放出が止まるということです。
ソースObservableによって発行された各アイテムに指定した関数を適用することに基づいて、アイテムを発行するObservableを返します。この関数は、(いわゆる「内部」)Observableを返します。これらの内部Observableの1つを監視するたびに、出力Observableは、その内部Observableによって発行されたアイテムの発行を開始します。新しい内部Observableが放出されるとswitchMap 、以前に放出された内部Observableからのアイテムの放出を停止し、新しい内部Observableからのアイテムの放出を開始します。後続の内部オブザーバブルでは、引き>続きこのように動作します。