RxJSをはじめよう 〜FetchからSubject queueに至るまで〜

### 「Ionicで作る モバイルアプリ制作入門」刊行記念 Ionic Meetup Tokyo #3
https://ionic-jp.connpass.com/event/74895/

2018年1月28日

---

### 今回のサンプルコード

https://github.com/ovrmrw/ionic-subject-queue

---

## 自己紹介

ちきさん (Tomohiro Noguchi)

Qiita/Twitter/GitHub: @ovrmrw 

市ヶ谷にあるオプトという会社で働いています。

![3a2512bb-aa72-4515-af42-1f1721252f39.jpg](https://qiita-image-store.s3.amazonaws.com/0/74793/79620f87-200f-f153-5beb-a6e0476e9602.jpeg)

---

## 初めてRx(C#)に触れたときの感想

- 解説しているブログとか読んでも、なにをいっているのかさっぱりワカラナイ。
- hotとかcoldとか意味不明。
- flatMapとか異次元すぎる。
- ようやく到達した理解が「Rxはイベントハンドリングするためのライブラリ」だった。

---

## 初めて理解したRx(C#)

`Observable.fromEvent`

- テキストボックスの入力イベントをハンドリングし、何らかの処理に繋げられる。
- `debounce`を使うことでイベントを間引くことができる。

===

初めて`Observable.fromEvent`を使って書いたコードが動いたときはかなり感動しました。

---

## なので`Observable.fromEvent`を織り交ぜたLTをすればRxJSの良さをより伝えられるのではないかと考えた。

---

ここから本編

---

# Ionicにおける代表的なRxJSを使うパターン

---

## HttpClient と AsyncPipe

- これらは使い手が意識しなくても非同期処理を**Observable空間**に閉じていい感じに**自動キャンセルとかしてくれる。**
- 後始末(`unsubscribe`)を勝手にやってくれる。
- 組み合わせて使っておけばそれでだいたいオッケー。

---

## HttpClient と AsyncPipe に足りないもの

- 入力を間引く仕組み。(`debounce`)
- 例えばキーボード入力に応じて検索を実行する場合、「ionic」という入力に対して「i」,「io」,「ion」,「ioni」,「ionic」の全てで非同期処理(リクエスト)を発生させると最後以外は無駄になる。
- Cloud FunctionsとかAWS Lambdaみたいな仕組みでAPIを構築している場合、無駄に多く叩かれるとうれしくない。:disappointed_relieved:
- AsyncPipeを使うとtemplateに非同期処理を持ち込むことになるのでごちゃごちゃする。(このへんは好みの問題)

---

# 無駄の多い非同期処理から、無駄のない非同期処理まで5つのパターン とそのデモ

---

Ionic Viewアプリ用 

public AppID: **3c5bd0d9**

---

非同期処理のパターン 1

# Fetch (AsyncPipeなし)

リクエスト投げっぱなしの**最悪パターン。**

---

## Fetch (AsyncPipeなし)

- 全ての入力が新しいリクエストを発生させる。キャンセル不可。
- それらは並列で走る。
- **Viewへの反映が最後の入力に対する結果である保証はない。**

(デモ: Fetchページ)

---

非同期処理のパターン 2

# Fetch (AsyncPipeあり)

とりあえずキューイングを導入しただけの**「無いよりマシ」パターン。**

---

## Fetch (AsyncPipeあり)

- 全ての入力が新しいリクエストを発生させる。キャンセル不可。
- それらは**AsyncPipeによりキューイングされる。**
- Viewへの反映が最後の入力に対する結果であることは**保証される**が、それまでのレスポンスを**全て待たなければならない。**

(デモ: Fetch with AsyncPipeページ)

---

非同期処理のパターン 3

# HttpClient (AsyncPipeあり)

Ionic(Angular)の標準パターン。

---

## HttpClient (AsyncPipeあり)

- 全ての入力が新しいリクエストを発生させるが、**必要に応じて自動キャンセルされる。**
- それらはAsyncPipeによりキューイングされる。
- Viewへの反映が最後の入力に対する結果であることは保証されるし、不要なリクエストはキャンセルされるので**無駄な待ちがない。**

(デモ: HttpClient with AsyncPipeページ)

---

非同期処理のパターン 4

# HttpClient with Observable.fromEvent (AsyncPipeなし)

次のSubject queueを説明するための踏み台。

---

## HttpClient with Observable.fromEvent (AsyncPipeなし)

- 入力イベントをキューイングすることで**AsyncPipeが不要になりtemplateがスッキリする。**(好みの問題ではある)
- `switchMap`オペレーターの中で`HttpClient`を使っているので**自動キャンセルは有効。**
- オペレーターを駆使することで**必要以上にAPIを叩かない**仕組みを作れる。
- イベントハンドリングの記述が独特な書き方になるのでコードは読みにくい。

(デモ: HttpClient with Observable.fromEventページ)

---

非同期処理のパターン 5

# HttpClient with Subject queue (AsyncPipeなし)

:arrow_heading_up::arrow_heading_up: 要するに今日はこれを話したかった。 :arrow_heading_up::arrow_heading_up:

---

## HttpClient with Subject queue (AsyncPipeなし)

- `Subject`を使ってキューイングしている。
- `Observable.fromEvent`の例のメリットを踏襲しつつ、**Angularっぽさのあるコードで読みやすい。**

(デモ: HttpClient with Subject queueページ)

---

# Subjectを使えばなんでもできる :muscle:

---

(おまけ) RxJS関連で書いたもの

- [RxJSのconcatMap, mergeMap, switchMapの違いを理解する(中級者向け)](https://qiita.com/ovrmrw/items/b45d7bf29c8d29415bd7)
- [UXの高い「いいね」ボタンをRxJSで実装する](https://qiita.com/ovrmrw/items/bf1691fab3579f0d1075)
- [Sleep SortをRxJSで書いた](https://qiita.com/ovrmrw/items/bdd5d4f29368f6645a10)
- [RxJSでひとまとめの複数の非同期処理のうち一つでもエラーになったら他の全ての非同期処理を破棄するコードを書いた](https://qiita.com/ovrmrw/items/1fbbb92f2c766734c752)
- [RxJSのソースコードを読むにはミニマムなオレオレRxを書くのが一番早い](https://qiita.com/ovrmrw/items/9fec11948799441eb5cd)

---

## Thanks! :raised_hands: