サイトトップ

Director Flash 書籍 業務内容 プロフィール

HTML5テクニカルノート

RxJS入門 06: オペレータ


RxJSの基礎となるのはObservableです。オペレータはObservableを操作するのにとても役立ちます。複雑な非同期の処理を、わかりやすいコードで組み立てられるのです。公式「Manual」の「Operators」を下じきに、サンプルコードや解説は改めました。

01 オペレータとは

オペレータはObservableオブジェクトのメソッドです。map()filter()あるいはmerge()などが備わっています。オペレータを呼び出しても参照したインスタンスは変えません。Subscriptionの定めを受け継いだ新たなObservableが返されるのです。オペレータは、もとのObservableはそのままに、新たなObservableをつくる純粋な関数といえます。

オペレータは、基本的にひとつのObservableを入力として受け取り、もうひとつの新たなObservableをつくって返す関数です。出力Observableをサブスクライブすると、入力Observableもサブスクライブされます。つぎのコードで定めたカスタムオペレータ関数は、入力Observableから受け取る値をそれぞれ2乗します。出力オブジェクトに対してObservable.subscribe()メソッドを呼び出したとき、入力Observableもサブスクライブされることにご注目ください(後述のとおりObservable.subscribe()は静的オペレータです)。 これを「オペレータサブスクリプションチェーン」と呼びます。


function square(input) {
	const output = Rx.Observable.create((observer) => {
		input.subscribe({
			next(value) {observer.next(value ** 2);},
			error(err) {observer.error(err);},
			complete() {observer.complete();}
		});
	});
	return output;
}
const input = Rx.Observable.from([1, 2, 3, 4]);
const output = square(input);
output.subscribe((x) => console.log(x));

/* コンソール出力
1
4
9
16
*/

02 インスタンスオペレータと静的オペレータ

オペレータを参照するとき、多くの場合はObservableインスタンスのメソッドを考えます。たとえば、前掲コードのカスタムオペレータ関数(square())が、RxJSのインスタンスオペレータに組み込まれていたとしたら、以下のような実装になるでしょう。

インスタンスオペレータは、this参照を入力Observableとして扱う関数です。ですから、オペレータの引数に入力Observableは渡しません。参照するオブジェクトを入力とみなすのがインスタンスオペレータです。


Rx.Observable.prototype.square = function() {
	return Rx.Observable.create((observer) => {
		this.subscribe({
			next(value) {observer.next(value ** 2);},
			error(err) {observer.error(err);},
			complete() {observer.complete();}
		});
	});
}
const observable = Rx.Observable.from([1, 2, 3, 4]).square();
observable.subscribe((x) => console.log(x));

/* コンソール出力
1
4
9
16
*/

インスタンスオペレータのほかに、Observableクラスに直接定められた関数である静的オペレータがあります。静的オペレータはthis参照をもちません。引数にもとづいて、新たなObservableを返します。Observableインスタンスを新しくつくりたいときに用いられることが多いでしょう。

よく使われる静的オペレータは、生成オペレータです。入力Observableから出力Observableに変換するのではなく、引数に数値のようなObservableでない値を受け取って、新しくObservableをつくります。静的オペレータの典型として挙げられるのはinterval()です。引数はObservableでなく数値で、新しくObservableをつくって出力として返します。


const observable = Rx.Observable.interval(1000);
const subscription = observable.subscribe((x) => console.log(x));
setTimeout(() => 
	subscription.unsubscribe()
, 3000);

/* コンソール出力
0
1
*/

静的生成オペレータのもうひとつの例としては、すでにこれまでもたびたび使ってきたObservable.create()があります。生成オペレータにどのようなものがあるかは、「Creation Operators」をご覧ください。

インスタンスをただつくるだけではない静的オペレータもあります。結合オペレータには、Observable.merge()Observable.combineLatest()あるいはObservable.concat()など静的なものがあります(「Combination Operators」参照)。これらは、複数の入力Observableを引数に受け取るために、静的オペレータとされたのです。

Observable.merge()メソッドは、引数のふたつの入力Observableがひとつにまとめられた出力Observableをつくって返します。つぎのコードでは、observable2から送られる値のふたつおきに、observable1の値が送り出されています。なお、take()メソッドObservableから送られる値の数を引数値に止めます。


const observable1 = Rx.Observable.interval(1000).take(3);
const observable2 = Rx.Observable.interval(400).take(6);
const merged = Rx.Observable.merge(observable1, observable2);
merged.subscribe((x) => console.log(x));
/* コンソール出力
0
1
0  // observable1
2
3
1  // observable1
4
5
2  // observable1
*/

03 マーブルダイヤグラム

オペレータの働きを、文章だけで説明しようとするとかぎりがあります。オペレータの多くは時間に関わり、sample()throttle()あるいはdebounce()など異なったやり方で値を送ります。それらは、図で説明するとわかりやすくなることが少なくありません。マーブルダイヤグラム(Marble Diagram)は、オペレータの働きを図で示したものです。その中には、入力Observableやオペレータとその引数、さらに出力Observableが含まれます。

つぎ図001が、マーブルダイヤグラムの例です。時間は左から右に流れ、マーブルで示された値がObservableの実行によりどのように送られるのかを表しています。RxJS公式ドキュメントでは、マーブルダイヤグラムでオペレータの仕組みを説明しています。

図001■マーブルダイアログとその説明

04 オペレータの選択と分類

04-01 オペレータを選ぶ

RxJS公式サイトの「Choose an operator」では、リスト(英語)から求める項目を選んでゆくと適切なオペレータが示されます。

04-02 オペレータの分類

RxJSには、さまざまな目的のオペレータがあります。それらを分類したのが以下のリストです。分類項目はRxJS公式「Manual」の「Categories of operators」にリンクされており、それぞれの分類のオペレータが一覧でみられます。

RxJS入門


作成者: 野中文雄
作成日: 2018年4月2日


Copyright © 2001-2018 Fumio Nonaka.  All rights reserved.