RxJS の Operators (5) - Observable の結合 (2)

この記事は [bouzuya's RxJS Advent Calendar 2015](http://www.adventar.org/calendars/1200) の 7 日目かつ RxJS Advent Calendar 2015 の 7 日目です。

# はじめに

今日も昨日に続いて [ReactiveX の Operators の Combining](http://reactivex.io/documentation/operators.html#combining) について [RxJS の API ドキュメント](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/doc/api/core/observable.md)やソースコードを見ていきます。

また [RxJS 4.0.7](https://github.com/Reactive-Extensions/RxJS/tree/v4.0.7) を対象にしています。

# Observable の結合 (2)

## `Observable.concat` / `Observable.prototype.concat`

- [ReactiveX - Concat operator](http://reactivex.io/documentation/operators/concat.html)
- [`Observable.concat` API Document](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/doc/api/core/operators/concat.md)
- [`Observable.concat` Source Code](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/src/core/perf/operators/concat.js)

`Observable.concat` と `Observable.prototype.concat` とはほとんど同じものです。どちらも最初の `Observable` の `onCompleted` で concat した次の `Observable` に switch していくイメージです。

```js
import { Observable } from 'rx';

Observable
  .concat(
    Observable.from([1, 2, 3]),
    Observable.from(['A', 'B'])
  )
  .subscribe(
    value => console.log(`onNext: ${value}`),
    error => console.log(`onError: ${error}`),
    () => console.log('onCompleted')
  );
// onNext: 1
// onNext: 2
// onNext: 3
// onNext: A
// onNext: B
// onCompleted
```

ちなみに `Observable.prototype.concatAll` は `Observable.prototype.merge(1)` (maxConcurrent = 1) で、 `Observable.prototype.concatMap` は `map(selector).concatAll()` です。

## `Observable.prototype.join`

- [ReactiveX - Join operator](http://reactivex.io/documentation/operators/join.html)
- [`Observable.prototype.join` API Document](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/doc/api/core/operators/join.md)
- [`Observable.prototype.join` Source Code](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/src/core/linq/observable/join.js)

`Observable.prototype.join` は `Array.prototype.join` とは違います。どちらかというと SQL で table を join するイメージで、ふたつの `Observable` を join して、すべての組み合わせを列挙します。

第二・第三引数で、それぞれの値をどれだけの期間利用するかを指定できます。`Observable.never()` とすれば値は延々と使われます。

```js
import { Observable } from 'rx';

const left = Observable.from([1, 2]).map(value => `l:${value}`);
const right = Observable.from([3, 4]).map(value => `r:${value}`)

left
  .join(
    right,
    () => Observable.never(),
    () => Observable.never(),
    (x, y) => `${x},${y}`
  )
  .subscribe(
    value => console.log(`onNext: ${value}`),
    error => console.log(`onError: ${error}`),
    () => console.log('onCompleted')
  );
// onNext: l:1,r:3
// onNext: l:2,r:3
// onNext: l:1,r:4
// onNext: l:2,r:4
// onCompleted
```

`left` や `right` を `interval(100)` で区切ったり、`never()` を `timer(0)` などに変えると動きの変化が見れると思います。

ただ、ぼくにはこれを使いこなせる気がしません。

## `Observable.prototype.and` / `Observable.prototype.thenDo` / `Observable.when`

- [ReactiveX - And/Then/When operator](http://reactivex.io/documentation/operators/and-then-when.html)
- [`Observable.prototype.and` API Document](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/doc/api/core/operators/and.md)
- [`Observable.prototype.and` Source Code](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/src/core/linq/observable/and.js)
- [`Observable.prototype.thenDo` API Document](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/doc/api/core/operators/thendo.md)
- [`Observable.prototype.thenDo` Source Code](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/src/core/linq/observable/thendo.js)
- [`Observable.when` API Document](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/doc/api/core/operators/when.md)
- [`Observable.when` Source Code](https://github.com/Reactive-Extensions/RxJS/blob/v4.0.7/src/core/linq/observable/when.js)

`Observable.when(observable1.and(observable2).thenDo(selector), ...)`

といった形で使用します。

```
when
  condition then do
  condition then do
```

っぽい構文をつくりたいのでしょうか……。

実装を軽く読むと

- `Observable.when` は複数の `Plan` を引数にとって、それぞれを `activate` していく。
- `Observable.prototype.and` は `new Pattern([this, right])` 。
- `Observable.prototype.thenDo` は `new Pattern([this]).thenDo(selector)` 。
- `Pattern.prototype.thenDo` は `new Plan(this, selector)` 。

という感じ。

要するに `observable` を複数束ねた `Pattern` と、`Pattern` に `selector` を加えた `Plan` とを用意して、実行すると。

複数の Observable を細かい制御をしながら結合してひとつの Observable をつくりたいのでしょうが、正直なところ、この構文の何が嬉しいのか、ぼくにはまだ分かっていないです。

# おわりに

今日は `Observable` を結合する Operator の続きを書きました。

ぼくの理解力だとよく分からないものが多くて困ります。この Advent Calendar が終わるころには分かるようになるのでしょうか。