58
RxJSの中を追う 安福 一樹 (wilfrem, @WilfremLuminous)

歌舞伎座tech発表資料 RxJSの中を追う

  • Upload
    wilfrem

  • View
    2.451

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 歌舞伎座tech発表資料 RxJSの中を追う

RxJSの中を追う

安福 一樹 (wilfrem, @WilfremLuminous)

Page 2: 歌舞伎座tech発表資料 RxJSの中を追う

自己紹介

名前: 安福 一樹 HN: wilfremとか@WilfremLuminous

仕事 Webエンジニア。 主にサーバサイドの開発をしています。 最近新部署に異動しました。

趣味 最近は面白技術を色々試して遊んでいる

Page 3: 歌舞伎座tech発表資料 RxJSの中を追う

はじめに

Page 4: 歌舞伎座tech発表資料 RxJSの中を追う

今日のタイトルについて

RxのHot/Coldを入り口に Rxが中で何をやっているかを追いたいと思います。

主に細かなところについて。

Rxにはどうしてもハマる点あるのですが Rxが中で何をやっているかが分かれば ハマりどころを回避できると思います。

Page 5: 歌舞伎座tech発表資料 RxJSの中を追う

対象プラットフォームについて

RxJS中心のお話になっていますが Rx.NET/RxJavaの実装と見比べてみたところ 言語ごとの実装に大きな違いはなく

Rx.NET/RxJavaでも使える話になります

スケジューラーしか大きな違いが無かった オペレータ名が微妙に違うのも LINQ引きずってる.NETだけの話だし

Page 6: 歌舞伎座tech発表資料 RxJSの中を追う

本編

Page 7: 歌舞伎座tech発表資料 RxJSの中を追う

まずはこの問題のコードを御覧ください

“side effect”は何回表示されるか?

var rx = require("rx"); var s = new rx.Subject(); var stream = s.tap(function(){console.log("side effect");}); stream.subscribeOnNext(function(){}); stream.subscribeOnNext(function(){}); s.onNext("foo");

ちょっと読みにくいので図にします

Page 8: 歌舞伎座tech発表資料 RxJSの中を追う

図にしてみた

side effectは何回表示されるでしょうか?

subject tap(do)

side effect message

onNext

nop

nop

Page 9: 歌舞伎座tech発表資料 RxJSの中を追う

答え

2回

subject tap(do)

side effect message

onNext

nop

nop side effect

Page 10: 歌舞伎座tech発表資料 RxJSの中を追う

なぜ二回なのか?

よくある説明 「doはColdなObservableだ」

→とても表面的な説明と理解 説明が良くない

現象の正しい理解のために Rxの動作原理を追ってみる

Page 11: 歌舞伎座tech発表資料 RxJSの中を追う

Rxのおさらい

Page 12: 歌舞伎座tech発表資料 RxJSの中を追う

Rxの基本要素

Rxのストリームと3種のメッセージ

onNext* (onCompleted|onError)?

onNext onNext onNext onCompleted

Page 13: 歌舞伎座tech発表資料 RxJSの中を追う

ObservableとObserver

onNext(msg: T)

onCompleted()

onError(error: any)

Observer<T> Observable<T>

subscribe(o: Observer<T>)

1. subscribeする

2. つながる

3. messageがpushされる

Page 14: 歌舞伎座tech発表資料 RxJSの中を追う

Observableとオペレータ

map filter throttle

Observable map

オペレータ=Observableを返す関数

RxにはObservableのメンバに様々なオペレータがある

Observable

Page 15: 歌舞伎座tech発表資料 RxJSの中を追う

オペレータのチェーン

map filter throttle Observable

Rxのオペレータは繋げられる

メッセージはオペレータに”加工”されて伝達する(onCompleted/onErrorも同様)

map filter throttle Observable Observer

message

onNext onNext onNext onNext

message subscribe

Page 16: 歌舞伎座tech発表資料 RxJSの中を追う

ところで……

Page 17: 歌舞伎座tech発表資料 RxJSの中を追う

オペレータはObservableである

オペレータを重ねられる

subscribeできる

→Observableである

Observable map

オペレータはObservableである

Observable

Page 18: 歌舞伎座tech発表資料 RxJSの中を追う

オペレータはObserverでもある?

Observableに繋げられる

メッセージを受け取れる

→Observerである

Observable map

オペレータはObserverでもある

Observer

message

Observer?いた?

Page 19: 歌舞伎座tech発表資料 RxJSの中を追う

しかし、オペレータの利用で

Observerを見かけることはない

Page 20: 歌舞伎座tech発表資料 RxJSの中を追う

Observerはどこにいるのか?

Page 21: 歌舞伎座tech発表資料 RxJSの中を追う

改めて: ObservableとObserver

onNext(msg: T)

onCompleted()

onError(error: any)

Observer<T> Observable<T>

subscribe(o: Observer<T>)

1. subscribeする

2. つながる

3. messageがpushされる

Page 22: 歌舞伎座tech発表資料 RxJSの中を追う

当然ですが、オペレータ=Observable

何度も説明したとおり、オペレータ=Observable

つまり、後ろのObserverにsubscribeされる

もちろん、後ろがオペレーターなら オペレーターがオペレーターをsubscribeする

どうやって……?

map filter throttle Observable Observer

subscribe

Page 23: 歌舞伎座tech発表資料 RxJSの中を追う

オペレーターがオペレーターを

Subscribeする方法とは?

Page 24: 歌舞伎座tech発表資料 RxJSの中を追う

答え: オペレータはObserverを生成する

Observerを「生成」する

1つ手前のObservableをsubscribeする

subscribeはチェーンする

map filter throttle Observable Observer

subscribe

throttleObserver

Page 25: 歌舞伎座tech発表資料 RxJSの中を追う

Subscribeが完了すると

最終的にObservableにチェーンが到達

結果的にSubscribeすると Observerのチェーンが生成される

map filter throttle Observable Observer

メッセージ メッセージ メッセージ

Page 26: 歌舞伎座tech発表資料 RxJSの中を追う

オペレータの内部実装

ObservableBase(的な物)がある =AnnonimousObservable

パフォーマンス改善verだと まさにObservableBaseが存在する

subscribeだけ差し替えられる

各オペレータはsubscribeの差し替えを実装

差し替え処理で手前をsubscribeしている

Page 27: 歌舞伎座tech発表資料 RxJSの中を追う

Rxの”Hot”とは?

Hot = Observerのチェーンを作ること。

Observerのチェーンを作るから メッセージが流れる

RxのHotとは subscribeしてチェーンを作成すること。

Page 28: 歌舞伎座tech発表資料 RxJSの中を追う

チェインの行き着く先について

Page 29: 歌舞伎座tech発表資料 RxJSの中を追う

チェインの行き着く先

一番先頭のObservableはどういう物か?

2種類のObservableが存在する

map filter throttle Observable Observer

Page 30: 歌舞伎座tech発表資料 RxJSの中を追う

タイプ1: “非保持型”

特徴 subscribeしてきたObserverを保持しない

何回subscribeしても同じ結果となる →例えばチェーンを何度も生成

例 just, create、大抵のオペレータなど

=”Cold Observable”、Coldな性質と呼ばれる

Page 31: 歌舞伎座tech発表資料 RxJSの中を追う

タイプ2: “保持型”

特徴 subscribeしてきたobservableをキャプチャする

必要になった時にメッセージを流す

流す対象をリストとして持ち、分配機能を持つ

例 publish, fromEvent, Subject

= “Hot Observable”、Hotな性質と呼ばれる

Hot/Coldが分かりにくいのは 用語間違っているからな気がしている

Page 32: 歌舞伎座tech発表資料 RxJSの中を追う

話をだいぶ戻して

side effectはなぜ2回表示されるか?

subject tap(do)

side effect message

onNext

nop

nop

もう分かりますよね。

Page 33: 歌舞伎座tech発表資料 RxJSの中を追う

こうなるから

subject tap(do)

side effect

message

onNext

nop

nop

side effect

tap observer

tap observer

Page 34: 歌舞伎座tech発表資料 RxJSの中を追う

では?

side effectを1回だけ表示させるには?

subject tap(do)

side effect message

onNext

nop

nop

Page 35: 歌舞伎座tech発表資料 RxJSの中を追う

答え

subjectを挟む

subject tap(do)

side effect message

onNext

nop

nop

subject

Page 36: 歌舞伎座tech発表資料 RxJSの中を追う

Subjectの役割

役割 SubjectはObserverをリストとして持つ

Observerとしてメッセージを受け取る

Observableとしてメッセージを配信する

Subjectを挟むと”保持型”になる =Cold→Hot変換の正体 publish, share, fromeventは 内部でSubject使っている

Page 37: 歌舞伎座tech発表資料 RxJSの中を追う

Cold→Hot変換のconnect()とは

Cold→Hot変換すると出てくる

ConnectableObservable

中にSubjectがいる。

ConnectableObservable = Subject

ConnectableObservable#connect()とは 内部のsubjectにsubscribeさせること。

Page 38: 歌舞伎座tech発表資料 RxJSの中を追う

改めて、Rxは中で何をやっているのか?

復習を兼ねて

Page 39: 歌舞伎座tech発表資料 RxJSの中を追う

Rxの構成要素

Rxは (乱暴めに言うと) 5つの要素で構成されている

Observable Observer

ObserverとObservable

BaseObservableと オペレータ

subject operator

SubjectとHot

onNext* (onCompleted | onError)?

scheduler

Scheduler

おまけで解説します

ストリーム

Page 40: 歌舞伎座tech発表資料 RxJSの中を追う

Observableとオペレーター

Observableに Operatorを繋げて 次のObservableを得られる

Observable

Observable operator

Observable

Page 41: 歌舞伎座tech発表資料 RxJSの中を追う

Observableとオペレーターの関係

オペレータは 手前の参照を持つ

後ろの参照はしない

メッセージは まだ流れない

この状態=Cold

Observable operator

参照

参照せず

Page 42: 歌舞伎座tech発表資料 RxJSの中を追う

Operatorの仕組み

オペレータはほぼ処理が共通 =ObservableBase

subscribeを差し替えられるのみ

Operator extends ObservableBase<T>

subscribe(o: Observer<T>)

差し替え可能

Rxのオペレータは多数存在するが 大半はここの差し替えの違いのみ

Page 43: 歌舞伎座tech発表資料 RxJSの中を追う

subscribe差し替えの例

filter

条件に一致した時に 次にメッセージを流すObserverを 作成する

map

メッセージを変換して流す Observerを作成する

Page 44: 歌舞伎座tech発表資料 RxJSの中を追う

subscribeの連鎖

Subscribe連鎖

Subscribeで 後ろのObserverを知る

Observerのチェーンが作成される

Observable operator

subscribe

Observer

Observer

参照

Page 45: 歌舞伎座tech発表資料 RxJSの中を追う

ストリームの作動

連鎖が完了 →Observerのチェーンが完成

これで「作動」し メッセージが流れる →Hotになる

Observable operator Observer

Observer メッセージ

Page 46: 歌舞伎座tech発表資料 RxJSの中を追う

Cold “Observable”とHot “Observable”

Cold “Observable”

Observer非保持

オペレータなら subscribeごとに チェーンを生成

Hot “Observable”

Observer保持

分配機能を持つ

Subjectでできている

Page 47: 歌舞伎座tech発表資料 RxJSの中を追う

メッセージの伝搬

Observer

onNext()

onCompleted()

onError()

Observer

onNext()

onCompleted()

onError()

message message message

Page 48: 歌舞伎座tech発表資料 RxJSの中を追う

メッセージはSubscribeに到達する

Observer

onNext()

onCompleted()

onError()

subscriber

subscribeOnNext()

subscribeOnCompleted()

subscribeOnError()

message message

Page 49: 歌舞伎座tech発表資料 RxJSの中を追う

ストリームの終了

disposeを呼ぶか ストリームが終了で チェーンは消滅 Observable operator Observer

Observer

Observable operator Observer

dispose()

Page 50: 歌舞伎座tech発表資料 RxJSの中を追う

以上がRxの中身になります

Page 51: 歌舞伎座tech発表資料 RxJSの中を追う

おまけ: Schedulerについて

流れ的に入らなかった……

Page 52: 歌舞伎座tech発表資料 RxJSの中を追う

スケジューラーとは

実行する関数をイベントキューに積む機構

メッセージの送信タイミングを変えられる

スレッドも変えられる

関数

イベントキュー

スレッド・イベントループ

関数

関数

キューに積む 実行

Page 53: 歌舞伎座tech発表資料 RxJSの中を追う

Schedulerの実装

Rxの実装方法は言語によって違いはない

例外がScheduler

スレッドが使えるかどうか? イベントループはあるか?

Page 54: 歌舞伎座tech発表資料 RxJSの中を追う

Rx.NET/RxJavaのScheduler

出来ること スレッド切り替え(新規スレッド・ワーカー)

スレッド同期

イベントキューへの積み込み

etc.

大体の物は用意されている

Page 55: 歌舞伎座tech発表資料 RxJSの中を追う

RxJSにおけるScheduler

イベントループに積む/積まないのみ。 シングルスレッドですし……

Scheduler.defaultが使える

積む関数は適切に選ばれる node.jsはsetImmediate→nextTick

ブラウザはsetImmediate→MessageChannnel→

postMessage→onReadyStateChanged→ setTimeout

Page 56: 歌舞伎座tech発表資料 RxJSの中を追う

スケジューラーの使いどころ

重たい処理

処理を一息つかせたい時

スレッド切り替え/同期したい時

Page 57: 歌舞伎座tech発表資料 RxJSの中を追う

observeOnとsubscribeOnの違い

observeOn

メッセージが来た時

メッセージ処理に イベントループや スレッド切り替えを挟む

subscribeOn

subscribe時の チェーン生成時

チェーン生成の スレッドを変えられる

何に使うんだろ?

Page 58: 歌舞伎座tech発表資料 RxJSの中を追う

以上です

ご清聴ありがとうございました